@tscircuit/cli 0.1.2071 → 0.1.2072

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/lib/index.js CHANGED
@@ -69109,7 +69109,7 @@ var getNodeHandler = (winterSpec, { port, middleware = [] }) => {
69109
69109
  }));
69110
69110
  };
69111
69111
  // package.json
69112
- var version = "0.1.2070";
69112
+ var version = "0.1.2071";
69113
69113
  var package_default = {
69114
69114
  name: "@tscircuit/cli",
69115
69115
  version,
@@ -69160,7 +69160,7 @@ var package_default = {
69160
69160
  "circuit-json-to-fdm-component-box": "^0.0.2",
69161
69161
  "circuit-json-to-footprinter": "^0.0.54",
69162
69162
  "circuit-json-to-gerber": "^0.0.105",
69163
- "circuit-json-to-kicad": "0.0.181",
69163
+ "circuit-json-to-kicad": "0.0.212",
69164
69164
  "circuit-json-to-pnp-csv": "^0.0.13",
69165
69165
  "circuit-json-to-readable-netlist": "^0.0.15",
69166
69166
  "circuit-json-to-spice": "^0.0.45",
@@ -71848,6 +71848,7 @@ import {
71848
71848
  TextEffectsFont,
71849
71849
  TextEffectsJustify
71850
71850
  } from "kicadts";
71851
+ import { TitleBlock, TitleBlockComment } from "kicadts";
71851
71852
  import {
71852
71853
  EmbeddedFonts,
71853
71854
  LibSymbols,
@@ -71855,26 +71856,25 @@ import {
71855
71856
  SymbolPinNames,
71856
71857
  SymbolPinNumbers
71857
71858
  } from "kicadts";
71858
- import { symbols as symbols2 } from "schematic-symbols";
71859
+ import { symbols as symbols3 } from "schematic-symbols";
71859
71860
  import { symbols } from "schematic-symbols";
71861
+ import { symbols as symbols2 } from "schematic-symbols";
71860
71862
  import { SchematicSymbol } from "kicadts";
71861
71863
  import {
71862
71864
  compose,
71863
71865
  scale as createScaleMatrix,
71864
71866
  translate
71865
71867
  } from "transformation-matrix";
71866
- import { Pts, Stroke as Stroke2, SymbolPolyline, SymbolPolylineFill, Xy } from "kicadts";
71868
+ import { SymbolArc } from "kicadts";
71867
71869
  import { applyToPoint } from "transformation-matrix";
71868
- import {
71869
- Stroke as Stroke3,
71870
- SymbolCircle,
71871
- SymbolCircleCenter,
71872
- SymbolCircleFill,
71873
- SymbolCircleRadius
71874
- } from "kicadts";
71870
+ import { SymbolCircle } from "kicadts";
71875
71871
  import { applyToPoint as applyToPoint2 } from "transformation-matrix";
71876
- import { SymbolText, TextEffects as TextEffects2, TextEffectsFont as TextEffectsFont2 } from "kicadts";
71872
+ import { Pts, Stroke as Stroke2, SymbolPolyline, SymbolPolylineFill, Xy } from "kicadts";
71877
71873
  import { applyToPoint as applyToPoint3 } from "transformation-matrix";
71874
+ import { SymbolRectangle } from "kicadts";
71875
+ import { applyToPoint as applyToPoint4 } from "transformation-matrix";
71876
+ import { SymbolText, TextEffects as TextEffects2, TextEffectsFont as TextEffectsFont2 } from "kicadts";
71877
+ import { applyToPoint as applyToPoint5 } from "transformation-matrix";
71878
71878
  import { SymbolProperty } from "kicadts";
71879
71879
  import { TextEffects as TextEffects3, TextEffectsFont as TextEffectsFont3 } from "kicadts";
71880
71880
  import {
@@ -71885,19 +71885,23 @@ import {
71885
71885
  TextEffects as TextEffects4,
71886
71886
  TextEffectsFont as TextEffectsFont4
71887
71887
  } from "kicadts";
71888
- import { applyToPoint as applyToPoint4, scale as createScaleMatrix2 } from "transformation-matrix";
71888
+ import { applyToPoint as applyToPoint6, scale as createScaleMatrix2 } from "transformation-matrix";
71889
71889
  import {
71890
71890
  Polyline,
71891
71891
  Pts as Pts2,
71892
+ SchematicArc,
71893
+ SchematicRectangle,
71892
71894
  SchematicText,
71893
- Stroke as Stroke4,
71895
+ Stroke as Stroke3,
71896
+ SymbolArcFill,
71897
+ SymbolRectangleFill,
71894
71898
  TextEffects as TextEffects5,
71895
71899
  TextEffectsFont as TextEffectsFont5,
71896
71900
  TextEffectsJustify as TextEffectsJustify2,
71897
71901
  Uuid,
71898
71902
  Xy as Xy2
71899
71903
  } from "kicadts";
71900
- import { applyToPoint as applyToPoint5 } from "transformation-matrix";
71904
+ import { applyToPoint as applyToPoint7 } from "transformation-matrix";
71901
71905
  import {
71902
71906
  SchematicSymbol as SchematicSymbol5,
71903
71907
  SymbolLibId,
@@ -71911,8 +71915,8 @@ import {
71911
71915
  TextEffectsJustify as TextEffectsJustify3,
71912
71916
  GlobalLabel
71913
71917
  } from "kicadts";
71914
- import { applyToPoint as applyToPoint6 } from "transformation-matrix";
71915
- import { symbols as symbols3 } from "schematic-symbols";
71918
+ import { applyToPoint as applyToPoint8 } from "transformation-matrix";
71919
+ import { symbols as symbols4 } from "schematic-symbols";
71916
71920
  import { formatSiUnit } from "format-si-unit";
71917
71921
  import {
71918
71922
  EmbeddedFonts as EmbeddedFonts2,
@@ -71929,10 +71933,9 @@ import {
71929
71933
  TextEffectsFont as TextEffectsFont7,
71930
71934
  TextEffectsJustify as TextEffectsJustify4
71931
71935
  } from "kicadts";
71932
- import { symbols as symbols4 } from "schematic-symbols";
71933
- import { applyToPoint as applyToPoint7 } from "transformation-matrix";
71934
- import { Wire, Pts as Pts3, Xy as Xy3, Stroke as Stroke5, Junction } from "kicadts";
71935
- import { applyToPoint as applyToPoint8 } from "transformation-matrix";
71936
+ import { applyToPoint as applyToPoint9 } from "transformation-matrix";
71937
+ import { Wire, Pts as Pts3, Xy as Xy3, Stroke as Stroke4, Junction } from "kicadts";
71938
+ import { applyToPoint as applyToPoint10 } from "transformation-matrix";
71936
71939
  import {
71937
71940
  SheetInstances,
71938
71941
  SheetInstancesRootPath,
@@ -72501,13 +72504,13 @@ import {
72501
72504
  ZonePolygon
72502
72505
  } from "kicadts";
72503
72506
  import {
72504
- applyToPoint as applyToPoint9,
72507
+ applyToPoint as applyToPoint11,
72505
72508
  compose as compose3,
72506
72509
  rotate,
72507
72510
  translate as translate3
72508
72511
  } from "transformation-matrix";
72509
72512
  import { Pts as Pts5, Xy as Xy5, Zone as Zone2, ZoneKeepout, ZonePolygon as ZonePolygon2 } from "kicadts";
72510
- import { applyToPoint as applyToPoint10 } from "transformation-matrix";
72513
+ import { applyToPoint as applyToPoint12 } from "transformation-matrix";
72511
72514
  import {
72512
72515
  Paper as Paper2,
72513
72516
  PcbLayers,
@@ -72528,7 +72531,7 @@ import {
72528
72531
  TextEffects as TextEffects8,
72529
72532
  TextEffectsFont as TextEffectsFont8
72530
72533
  } from "kicadts";
72531
- import { applyToPoint as applyToPoint18 } from "transformation-matrix";
72534
+ import { applyToPoint as applyToPoint22 } from "transformation-matrix";
72532
72535
  import {
72533
72536
  Property as Property2,
72534
72537
  TextEffects as TextEffects9,
@@ -72537,27 +72540,28 @@ import {
72537
72540
  FootprintModel as FootprintModel2,
72538
72541
  FootprintAttr as FootprintAttr2
72539
72542
  } from "kicadts";
72540
- import { FpCircle, Stroke as Stroke6 } from "kicadts";
72541
- import { FpCircle as FpCircle2, Stroke as Stroke7 } from "kicadts";
72542
- import { FpRect, Stroke as Stroke8 } from "kicadts";
72543
- import { FpRect as FpRect2, Stroke as Stroke9 } from "kicadts";
72544
- import { FpRect as FpRect3, Stroke as Stroke10 } from "kicadts";
72545
- import { FpPoly, Pts as Pts6, Stroke as Stroke11, Xy as Xy6 } from "kicadts";
72543
+ import { FpCircle, Stroke as Stroke5 } from "kicadts";
72544
+ import { applyToPoint as applyToPoint13, identity, rotate as rotate2 } from "transformation-matrix";
72545
+ import { FpCircle as FpCircle2, Stroke as Stroke6 } from "kicadts";
72546
+ import { FpRect, Stroke as Stroke7 } from "kicadts";
72547
+ import { FpRect as FpRect2, Stroke as Stroke8 } from "kicadts";
72548
+ import { FpRect as FpRect3, Stroke as Stroke9 } from "kicadts";
72549
+ import { FpPoly, Pts as Pts6, Stroke as Stroke10, Xy as Xy6 } from "kicadts";
72546
72550
  import {
72547
- applyToPoint as applyToPoint11,
72551
+ applyToPoint as applyToPoint14,
72548
72552
  compose as compose4,
72549
- rotate as rotate2,
72553
+ rotate as rotate3,
72550
72554
  scale as scale2,
72551
72555
  translate as translate4
72552
72556
  } from "transformation-matrix";
72553
72557
  import"kicadts";
72554
72558
  import { FpText, TextEffects as TextEffects10, TextEffectsFont as TextEffectsFont10 } from "kicadts";
72555
- import { applyToPoint as applyToPoint12, rotate as rotate3, identity } from "transformation-matrix";
72559
+ import { applyToPoint as applyToPoint15, rotate as rotate4, identity as identity2 } from "transformation-matrix";
72556
72560
  import { TextEffectsJustify as TextEffectsJustify5 } from "kicadts";
72557
- import { FpLine, Stroke as Stroke12 } from "kicadts";
72558
- import { applyToPoint as applyToPoint13, identity as identity2, rotate as rotate4 } from "transformation-matrix";
72561
+ import { FpLine, Stroke as Stroke11 } from "kicadts";
72562
+ import { applyToPoint as applyToPoint16, identity as identity3, rotate as rotate5 } from "transformation-matrix";
72559
72563
  import { FpText as FpText3, TextEffects as TextEffects11, TextEffectsFont as TextEffectsFont11 } from "kicadts";
72560
- import { applyToPoint as applyToPoint14, rotate as rotate5, identity as identity3 } from "transformation-matrix";
72564
+ import { applyToPoint as applyToPoint17, rotate as rotate6, identity as identity4 } from "transformation-matrix";
72561
72565
  import { FootprintModel as FootprintModel3 } from "kicadts";
72562
72566
  import {
72563
72567
  FootprintPad,
@@ -72569,22 +72573,24 @@ import {
72569
72573
  PadNet
72570
72574
  } from "kicadts";
72571
72575
  import {
72572
- applyToPoint as applyToPoint15,
72576
+ applyToPoint as applyToPoint18,
72573
72577
  compose as compose5,
72574
72578
  translate as translate5,
72575
72579
  scale as scale3,
72576
- rotate as rotate6
72580
+ rotate as rotate7
72577
72581
  } from "transformation-matrix";
72578
72582
  import { FootprintPad as FootprintPad2, PadDrill, PadNet as PadNet2 } from "kicadts";
72579
- import { applyToPoint as applyToPoint16, rotate as rotate7, identity as identity4 } from "transformation-matrix";
72583
+ import { applyToPoint as applyToPoint19, rotate as rotate8, identity as identity5 } from "transformation-matrix";
72580
72584
  import { FootprintPad as FootprintPad3, PadDrill as PadDrill2 } from "kicadts";
72581
- import { applyToPoint as applyToPoint17, rotate as rotate8, identity as identity5 } from "transformation-matrix";
72585
+ import { applyToPoint as applyToPoint20, rotate as rotate9, identity as identity6 } from "transformation-matrix";
72586
+ import { FpLine as FpLine2, Stroke as Stroke12 } from "kicadts";
72587
+ import { applyToPoint as applyToPoint21, identity as identity7, rotate as rotate10 } from "transformation-matrix";
72582
72588
  import { Segment, SegmentNet } from "kicadts";
72583
- import { applyToPoint as applyToPoint19 } from "transformation-matrix";
72589
+ import { applyToPoint as applyToPoint23 } from "transformation-matrix";
72584
72590
  import { Via, ViaNet } from "kicadts";
72585
- import { applyToPoint as applyToPoint20 } from "transformation-matrix";
72591
+ import { applyToPoint as applyToPoint24 } from "transformation-matrix";
72586
72592
  import { Footprint as Footprint4 } from "kicadts";
72587
- import { applyToPoint as applyToPoint21 } from "transformation-matrix";
72593
+ import { applyToPoint as applyToPoint25 } from "transformation-matrix";
72588
72594
  import { GrLine } from "kicadts";
72589
72595
  import {
72590
72596
  At as At3,
@@ -72593,10 +72599,10 @@ import {
72593
72599
  TextEffectsFont as TextEffectsFont12,
72594
72600
  TextEffectsJustify as TextEffectsJustify6
72595
72601
  } from "kicadts";
72596
- import { applyToPoint as applyToPoint22 } from "transformation-matrix";
72597
- import { applyToPoint as applyToPoint24, rotate as rotate9 } from "transformation-matrix";
72602
+ import { applyToPoint as applyToPoint26 } from "transformation-matrix";
72603
+ import { applyToPoint as applyToPoint28, rotate as rotate11 } from "transformation-matrix";
72598
72604
  import { GrText as GrText2, TextEffects as TextEffects13, TextEffectsFont as TextEffectsFont13, At as At4 } from "kicadts";
72599
- import { applyToPoint as applyToPoint23 } from "transformation-matrix";
72605
+ import { applyToPoint as applyToPoint27 } from "transformation-matrix";
72600
72606
  import { cju as cju3 } from "@tscircuit/circuit-json-util";
72601
72607
  import { cju as cju4 } from "@tscircuit/circuit-json-util";
72602
72608
  import { parseKicadSexpr as parseKicadSexpr2, KicadSch as KicadSch2 } from "kicadts";
@@ -72635,7 +72641,7 @@ function createSheetPropertyEffects(vertical) {
72635
72641
  justify: new TextEffectsJustify({ horizontal: "left", vertical })
72636
72642
  });
72637
72643
  }
72638
- function buildSheetNode(entry, rootUuid, x, y) {
72644
+ function buildSheetNode(entry, rootUuid, x, y, width, height) {
72639
72645
  const stroke = new Stroke;
72640
72646
  stroke.width = SHEET_BORDER_WIDTH;
72641
72647
  stroke.type = "solid";
@@ -72652,7 +72658,7 @@ function buildSheetNode(entry, rootUuid, x, y) {
72652
72658
  key: "Sheetfile",
72653
72659
  value: entry.filename,
72654
72660
  id: 1,
72655
- at: At.from([x, y + BOX_HEIGHT + 0.7, 0]),
72661
+ at: At.from([x, y + height + 0.7, 0]),
72656
72662
  effects: createSheetPropertyEffects("top")
72657
72663
  });
72658
72664
  const instancePath = new SheetInstancePath(`/${rootUuid}`);
@@ -72663,7 +72669,7 @@ function buildSheetNode(entry, rootUuid, x, y) {
72663
72669
  instances.projects = [instancesProject];
72664
72670
  return new Sheet({
72665
72671
  position: [x, y],
72666
- size: new SheetSize(BOX_WIDTH, BOX_HEIGHT),
72672
+ size: new SheetSize(width, height),
72667
72673
  excludeFromSim: false,
72668
72674
  inBom: true,
72669
72675
  onBoard: true,
@@ -72676,49 +72682,196 @@ function buildSheetNode(entry, rootUuid, x, y) {
72676
72682
  instances
72677
72683
  });
72678
72684
  }
72679
- function buildChildSheetNodes(children, rootUuid) {
72685
+ function buildChildSheetNodes(children, rootUuid, schematicSheetOptions = []) {
72680
72686
  const count = children.length;
72681
72687
  const cols = Math.max(1, Math.ceil(Math.sqrt(count)));
72682
72688
  const rows = Math.max(1, Math.ceil(count / cols));
72683
72689
  const nodes = [];
72690
+ let maximumRight = 0;
72691
+ let maximumBottom = 0;
72684
72692
  for (let index = 0;index < children.length; index++) {
72685
72693
  const col = index % cols;
72686
72694
  const row = Math.floor(index / cols);
72687
- const x = MARGIN + col * (BOX_WIDTH + GUTTER_X);
72688
- const y = MARGIN + row * (BOX_HEIGHT + GUTTER_Y);
72689
- nodes.push(buildSheetNode(children[index], rootUuid, x, y));
72695
+ const child = children[index];
72696
+ const hierarchyNode = schematicSheetOptions.find((sheetOptions) => sheetOptions.schematicSheetId === child.schematicSheetId)?.hierarchyNode;
72697
+ const x = hierarchyNode?.position.x ?? MARGIN + col * (BOX_WIDTH + GUTTER_X);
72698
+ const y = hierarchyNode?.position.y ?? MARGIN + row * (BOX_HEIGHT + GUTTER_Y);
72699
+ const width = hierarchyNode?.size.width ?? BOX_WIDTH;
72700
+ const height = hierarchyNode?.size.height ?? BOX_HEIGHT;
72701
+ nodes.push(buildSheetNode(child, rootUuid, x, y, width, height));
72702
+ maximumRight = Math.max(maximumRight, x + width);
72703
+ maximumBottom = Math.max(maximumBottom, y + height);
72690
72704
  }
72691
- const spanW = cols * BOX_WIDTH + (cols - 1) * GUTTER_X;
72692
- const spanH = rows * BOX_HEIGHT + (rows - 1) * GUTTER_Y;
72693
72705
  return {
72694
72706
  nodes,
72695
72707
  extentMm: {
72696
- width: 2 * MARGIN + spanW,
72697
- height: 2 * MARGIN + spanH
72708
+ width: maximumRight + MARGIN,
72709
+ height: maximumBottom + MARGIN
72698
72710
  }
72699
72711
  };
72700
72712
  }
72701
- function getSchematicBoundsAndCenter(db) {
72713
+ var DEFAULT_ROOT_FILENAME = "schematic.kicad_sch";
72714
+ function toFileBaseName(sheetName, fallbackIndex) {
72715
+ const baseName = sheetName.trim().toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
72716
+ return baseName.length > 0 ? baseName : `sheet_${fallbackIndex + 1}`;
72717
+ }
72718
+ function buildSchematicSheetPlan(circuitJson) {
72719
+ const rootUuid = crypto.randomUUID();
72720
+ const root = {
72721
+ schematicSheetId: null,
72722
+ sheetName: "Root",
72723
+ fileBaseName: "root",
72724
+ filename: DEFAULT_ROOT_FILENAME,
72725
+ pageNumber: "1",
72726
+ fileUuid: rootUuid
72727
+ };
72728
+ const schematicSheets = circuitJson.filter((el) => el.type === "schematic_sheet").slice().sort((a, b) => (a.sheet_index ?? 0) - (b.sheet_index ?? 0));
72729
+ const usedFileBaseNames = /* @__PURE__ */ new Set(["root"]);
72730
+ const children = [];
72731
+ for (let index = 0;index < schematicSheets.length; index++) {
72732
+ const sheet = schematicSheets[index];
72733
+ const sheetName = sheet.display_name ?? sheet.name ?? `Sheet ${index + 1}`;
72734
+ let fileBaseName = toFileBaseName(sheet.name ?? sheetName, index);
72735
+ if (usedFileBaseNames.has(fileBaseName)) {
72736
+ let suffix = 2;
72737
+ while (usedFileBaseNames.has(`${fileBaseName}_${suffix}`))
72738
+ suffix++;
72739
+ fileBaseName = `${fileBaseName}_${suffix}`;
72740
+ }
72741
+ usedFileBaseNames.add(fileBaseName);
72742
+ children.push({
72743
+ schematicSheetId: sheet.schematic_sheet_id,
72744
+ sheetName,
72745
+ fileBaseName,
72746
+ filename: `${fileBaseName}.kicad_sch`,
72747
+ pageNumber: `${index + 2}`,
72748
+ sheetNodeUuid: crypto.randomUUID(),
72749
+ fileUuid: crypto.randomUUID()
72750
+ });
72751
+ }
72752
+ return {
72753
+ rootUuid,
72754
+ root,
72755
+ children,
72756
+ isHierarchical: children.length > 0
72757
+ };
72758
+ }
72759
+ function createKicadSchematicTitleBlock(metadata) {
72760
+ if (!metadata)
72761
+ return;
72762
+ return new TitleBlock({
72763
+ company: metadata.company,
72764
+ comments: metadata.comments?.map(({ index, text }) => new TitleBlockComment(index, text)),
72765
+ date: metadata.date,
72766
+ rev: metadata.revision,
72767
+ title: metadata.title
72768
+ });
72769
+ }
72770
+ var componentPrimitiveTypes = /* @__PURE__ */ new Set([
72771
+ "schematic_path",
72772
+ "schematic_circle",
72773
+ "schematic_arc",
72774
+ "schematic_line",
72775
+ "schematic_rect"
72776
+ ]);
72777
+ function hasComponentLevelSymbolPrimitives(circuitJson, schematicComponent) {
72778
+ const schematicComponentId = schematicComponent.schematic_component_id;
72779
+ if (schematicComponent.is_box_with_pins !== false || schematicComponent.symbol_name || "schematic_symbol_id" in schematicComponent || circuitJson.some((element) => element.schematic_component_id === schematicComponentId && element.schematic_symbol_id)) {
72780
+ return false;
72781
+ }
72782
+ return circuitJson.some((element) => componentPrimitiveTypes.has(element.type) && element.schematic_component_id === schematicComponentId && !element.schematic_symbol_id);
72783
+ }
72784
+ function getSchematicBoundsAndCenter(db, {
72785
+ useComponentLevelSourceGeometry = false
72786
+ } = {}) {
72787
+ const circuitJson = db.toArray();
72702
72788
  const schematicComponents = db.schematic_component.list();
72703
72789
  const schematicTraces = db.schematic_trace.list();
72790
+ const schematicArcs = db.schematic_arc.list();
72791
+ const sourceGeometryComponentIds = new Set(schematicComponents.filter((component) => hasComponentLevelSymbolPrimitives(circuitJson, component)).map((component) => component.schematic_component_id));
72704
72792
  let minX = Infinity;
72705
72793
  let minY = Infinity;
72706
72794
  let maxX = -Infinity;
72707
72795
  let maxY = -Infinity;
72796
+ const includePoint = (point) => {
72797
+ minX = Math.min(minX, point.x);
72798
+ minY = Math.min(minY, point.y);
72799
+ maxX = Math.max(maxX, point.x);
72800
+ maxY = Math.max(maxY, point.y);
72801
+ };
72708
72802
  for (const component of schematicComponents) {
72803
+ if (useComponentLevelSourceGeometry && sourceGeometryComponentIds.has(component.schematic_component_id)) {
72804
+ continue;
72805
+ }
72709
72806
  const width = component.size?.width ?? 0;
72710
72807
  const height = component.size?.height ?? 0;
72711
- minX = Math.min(minX, component.center.x - width / 2);
72712
- minY = Math.min(minY, component.center.y - height / 2);
72713
- maxX = Math.max(maxX, component.center.x + width / 2);
72714
- maxY = Math.max(maxY, component.center.y + height / 2);
72808
+ includePoint({
72809
+ x: component.center.x - width / 2,
72810
+ y: component.center.y - height / 2
72811
+ });
72812
+ includePoint({
72813
+ x: component.center.x + width / 2,
72814
+ y: component.center.y + height / 2
72815
+ });
72715
72816
  }
72716
72817
  for (const trace of schematicTraces) {
72717
72818
  for (const edge of trace.edges) {
72718
- minX = Math.min(minX, edge.from.x, edge.to.x);
72719
- minY = Math.min(minY, edge.from.y, edge.to.y);
72720
- maxX = Math.max(maxX, edge.from.x, edge.to.x);
72721
- maxY = Math.max(maxY, edge.from.y, edge.to.y);
72819
+ includePoint(edge.from);
72820
+ includePoint(edge.to);
72821
+ }
72822
+ }
72823
+ for (const arc of schematicArcs) {
72824
+ includePoint({ x: arc.center.x - arc.radius, y: arc.center.y - arc.radius });
72825
+ includePoint({ x: arc.center.x + arc.radius, y: arc.center.y + arc.radius });
72826
+ }
72827
+ if (useComponentLevelSourceGeometry) {
72828
+ for (const line of db.schematic_line.list()) {
72829
+ if (!line.schematic_component_id || !sourceGeometryComponentIds.has(line.schematic_component_id)) {
72830
+ continue;
72831
+ }
72832
+ includePoint({ x: line.x1, y: line.y1 });
72833
+ includePoint({ x: line.x2, y: line.y2 });
72834
+ }
72835
+ for (const path of db.schematic_path.list()) {
72836
+ if (!path.schematic_component_id || !sourceGeometryComponentIds.has(path.schematic_component_id)) {
72837
+ continue;
72838
+ }
72839
+ for (const point of path.points)
72840
+ includePoint(point);
72841
+ }
72842
+ for (const rect of db.schematic_rect.list()) {
72843
+ if (!rect.schematic_component_id || !sourceGeometryComponentIds.has(rect.schematic_component_id)) {
72844
+ continue;
72845
+ }
72846
+ const halfWidth = rect.width / 2;
72847
+ const halfHeight = rect.height / 2;
72848
+ const rotationRadians = rect.rotation * Math.PI / 180;
72849
+ const cos = Math.cos(rotationRadians);
72850
+ const sin = Math.sin(rotationRadians);
72851
+ for (const corner of [
72852
+ { x: -halfWidth, y: -halfHeight },
72853
+ { x: halfWidth, y: -halfHeight },
72854
+ { x: halfWidth, y: halfHeight },
72855
+ { x: -halfWidth, y: halfHeight }
72856
+ ]) {
72857
+ includePoint({
72858
+ x: rect.center.x + corner.x * cos - corner.y * sin,
72859
+ y: rect.center.y + corner.x * sin + corner.y * cos
72860
+ });
72861
+ }
72862
+ }
72863
+ for (const circle of db.schematic_circle.list()) {
72864
+ if (!circle.schematic_component_id || !sourceGeometryComponentIds.has(circle.schematic_component_id)) {
72865
+ continue;
72866
+ }
72867
+ includePoint({
72868
+ x: circle.center.x - circle.radius,
72869
+ y: circle.center.y - circle.radius
72870
+ });
72871
+ includePoint({
72872
+ x: circle.center.x + circle.radius,
72873
+ y: circle.center.y + circle.radius
72874
+ });
72722
72875
  }
72723
72876
  }
72724
72877
  if (minX === Infinity) {
@@ -72730,6 +72883,7 @@ function getSchematicBoundsAndCenter(db) {
72730
72883
  const centerX = (minX + maxX) / 2;
72731
72884
  const centerY = (minY + maxY) / 2;
72732
72885
  return {
72886
+ hasComponentLevelSourceGeometry: sourceGeometryComponentIds.size > 0,
72733
72887
  center: {
72734
72888
  x: centerX,
72735
72889
  y: centerY
@@ -72742,6 +72896,45 @@ function getSchematicBoundsAndCenter(db) {
72742
72896
  }
72743
72897
  };
72744
72898
  }
72899
+ var PAPER_SIZES = [
72900
+ { name: "A4", width: 297, height: 210 },
72901
+ { name: "A3", width: 420, height: 297 },
72902
+ { name: "A2", width: 594, height: 420 },
72903
+ { name: "A1", width: 841, height: 594 },
72904
+ { name: "A0", width: 1189, height: 841 }
72905
+ ];
72906
+ function selectSchematicPaperSize(contentWidth, contentHeight, paddingMm = 20) {
72907
+ const requiredWidth = contentWidth + 2 * paddingMm;
72908
+ const requiredHeight = contentHeight + 2 * paddingMm;
72909
+ for (let i = 0;i < PAPER_SIZES.length; i++) {
72910
+ const paperSize = PAPER_SIZES[i];
72911
+ if (requiredWidth <= paperSize.width && requiredHeight <= paperSize.height) {
72912
+ return paperSize;
72913
+ }
72914
+ }
72915
+ return PAPER_SIZES[PAPER_SIZES.length - 1];
72916
+ }
72917
+ var DEFAULT_CONTENT_MARGIN_MM = 20;
72918
+ var KICAD_TITLE_BLOCK_HEIGHT_MM = 44;
72919
+ var TITLE_BLOCK_CLEARANCE_MM = 5;
72920
+ function getSchematicPageLayout({
72921
+ contentWidthMm,
72922
+ contentHeightMm,
72923
+ extraPaperExtentMm
72924
+ }) {
72925
+ const requiredWidthMm = Math.max(contentWidthMm + 2 * DEFAULT_CONTENT_MARGIN_MM, extraPaperExtentMm?.width ?? 0);
72926
+ const requiredHeightMm = Math.max(contentHeightMm + DEFAULT_CONTENT_MARGIN_MM + KICAD_TITLE_BLOCK_HEIGHT_MM + TITLE_BLOCK_CLEARANCE_MM, extraPaperExtentMm?.height ?? 0);
72927
+ const paperSize = selectSchematicPaperSize(requiredWidthMm, requiredHeightMm, 0);
72928
+ const centeredY = paperSize.height / 2;
72929
+ const lowestSafeCenterY = paperSize.height - KICAD_TITLE_BLOCK_HEIGHT_MM - TITLE_BLOCK_CLEARANCE_MM - contentHeightMm / 2;
72930
+ return {
72931
+ paperSize,
72932
+ contentCenter: {
72933
+ x: paperSize.width / 2,
72934
+ y: Math.min(centeredY, lowestSafeCenterY)
72935
+ }
72936
+ };
72937
+ }
72745
72938
  function isSchematicElement(el) {
72746
72939
  return typeof el.type === "string" && el.type.startsWith("schematic_");
72747
72940
  }
@@ -72750,9 +72943,7 @@ function keepElementForSheet(el, sheetId, componentIdsOnSheet) {
72750
72943
  return true;
72751
72944
  if (el.type === "schematic_sheet")
72752
72945
  return false;
72753
- const hasSheetIdField = "schematic_sheet_id" in el;
72754
- const hasComponentIdField = "schematic_component_id" in el;
72755
- if (!hasSheetIdField && !hasComponentIdField)
72946
+ if (el.type === "schematic_symbol")
72756
72947
  return true;
72757
72948
  if ((el.schematic_sheet_id ?? null) === sheetId)
72758
72949
  return true;
@@ -72776,70 +72967,6 @@ function partitionCircuitJsonBySheet(circuitJson, sheetId) {
72776
72967
  }
72777
72968
  return subset;
72778
72969
  }
72779
- var DEFAULT_ROOT_FILENAME = "schematic.kicad_sch";
72780
- function toFileBaseName(sheetName, fallbackIndex) {
72781
- const baseName = sheetName.trim().toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
72782
- return baseName.length > 0 ? baseName : `sheet_${fallbackIndex + 1}`;
72783
- }
72784
- function buildSchematicSheetPlan(circuitJson) {
72785
- const rootUuid = crypto.randomUUID();
72786
- const root = {
72787
- schematicSheetId: null,
72788
- sheetName: "Root",
72789
- fileBaseName: "root",
72790
- filename: DEFAULT_ROOT_FILENAME,
72791
- pageNumber: "1",
72792
- fileUuid: rootUuid
72793
- };
72794
- const schematicSheets = circuitJson.filter((el) => el.type === "schematic_sheet").slice().sort((a, b) => (a.sheet_index ?? 0) - (b.sheet_index ?? 0));
72795
- const usedFileBaseNames = /* @__PURE__ */ new Set(["root"]);
72796
- const children = [];
72797
- for (let index = 0;index < schematicSheets.length; index++) {
72798
- const sheet = schematicSheets[index];
72799
- const sheetName = sheet.display_name ?? sheet.name ?? `Sheet ${index + 1}`;
72800
- let fileBaseName = toFileBaseName(sheet.name ?? sheetName, index);
72801
- if (usedFileBaseNames.has(fileBaseName)) {
72802
- let suffix = 2;
72803
- while (usedFileBaseNames.has(`${fileBaseName}_${suffix}`))
72804
- suffix++;
72805
- fileBaseName = `${fileBaseName}_${suffix}`;
72806
- }
72807
- usedFileBaseNames.add(fileBaseName);
72808
- children.push({
72809
- schematicSheetId: sheet.schematic_sheet_id,
72810
- sheetName,
72811
- fileBaseName,
72812
- filename: `${fileBaseName}.kicad_sch`,
72813
- pageNumber: `${index + 2}`,
72814
- sheetNodeUuid: crypto.randomUUID(),
72815
- fileUuid: crypto.randomUUID()
72816
- });
72817
- }
72818
- return {
72819
- rootUuid,
72820
- root,
72821
- children,
72822
- isHierarchical: children.length > 0
72823
- };
72824
- }
72825
- var PAPER_SIZES = [
72826
- { name: "A4", width: 297, height: 210 },
72827
- { name: "A3", width: 420, height: 297 },
72828
- { name: "A2", width: 594, height: 420 },
72829
- { name: "A1", width: 841, height: 594 },
72830
- { name: "A0", width: 1189, height: 841 }
72831
- ];
72832
- function selectSchematicPaperSize(contentWidth, contentHeight, paddingMm = 20) {
72833
- const requiredWidth = contentWidth + 2 * paddingMm;
72834
- const requiredHeight = contentHeight + 2 * paddingMm;
72835
- for (let i = 0;i < PAPER_SIZES.length; i++) {
72836
- const paperSize = PAPER_SIZES[i];
72837
- if (requiredWidth <= paperSize.width && requiredHeight <= paperSize.height) {
72838
- return paperSize;
72839
- }
72840
- }
72841
- return PAPER_SIZES[PAPER_SIZES.length - 1];
72842
- }
72843
72970
  var ConverterStage = class {
72844
72971
  MAX_ITERATIONS = 1000;
72845
72972
  iteration = 0;
@@ -72880,6 +73007,12 @@ function getKicadCompatibleComponentName(sourceComponent, cadComponent) {
72880
73007
  }
72881
73008
  return sanitizeName(cleanType);
72882
73009
  }
73010
+ function getKicadCompatibleCustomSymbolName(sourceComponent, cadComponent, schematicSymbolId) {
73011
+ if (sourceComponent.manufacturer_part_number || cadComponent?.footprinter_string) {
73012
+ return getKicadCompatibleComponentName(sourceComponent, cadComponent);
73013
+ }
73014
+ return sanitizeName(`custom_${getCleanTypeName(sourceComponent.ftype)}_${schematicSymbolId}`);
73015
+ }
72883
73016
  function getCleanTypeName(ftype) {
72884
73017
  if (!ftype)
72885
73018
  return "component";
@@ -72889,7 +73022,7 @@ function getCleanTypeName(ftype) {
72889
73022
  return cleanName;
72890
73023
  }
72891
73024
  function sanitizeName(name) {
72892
- return name.replace(/[\\\/:\s]+/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "").trim() || "component";
73025
+ return name.replace(/[^A-Za-z0-9_-]+/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "").trim() || "component";
72893
73026
  }
72894
73027
  function extractReferencePrefix(name) {
72895
73028
  if (!name)
@@ -72946,6 +73079,9 @@ function getReferenceDesignator(sourceComponent) {
72946
73079
  function isBuiltinSymbol(symbolName) {
72947
73080
  return symbolName in symbols;
72948
73081
  }
73082
+ function sanitizeLibraryIdentifierPart(value) {
73083
+ return value.replace(/[^A-Za-z0-9_-]+/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "") || "connector";
73084
+ }
72949
73085
  function getLibraryId(sourceComp, schematicComp, cadComponent, schematicSymbolName) {
72950
73086
  if (schematicSymbolName) {
72951
73087
  return `Custom:${schematicSymbolName}`;
@@ -72967,12 +73103,63 @@ function getLibraryId(sourceComp, schematicComp, cadComponent, schematicSymbolNa
72967
73103
  }
72968
73104
  if (sourceComp.ftype === "simple_pin_header") {
72969
73105
  const pinCount = sourceComp.pin_count;
72970
- return `Connector_Generic:Conn_01x${pinCount}`;
73106
+ const instanceName = sanitizeLibraryIdentifierPart(sourceComp.name ?? schematicComp.schematic_component_id);
73107
+ return `Connector_Generic:Conn_01x${pinCount}_${instanceName}`;
72971
73108
  }
72972
73109
  const ergonomicName = getKicadCompatibleComponentName(sourceComp, cadComponent);
72973
73110
  const refPrefix = getReferencePrefixForComponent(sourceComp);
72974
73111
  return `Device:${refPrefix}_${ergonomicName}`;
72975
73112
  }
73113
+ function getComponentLevelLibraryId(sourceComp, schematicComp, cadComponent) {
73114
+ return `${getLibraryId(sourceComp, schematicComp, cadComponent)}_${sanitizeLibraryIdentifierPart(schematicComp.schematic_component_id)}`;
73115
+ }
73116
+ var legacySymbolNameByOrientedSymbolName = {
73117
+ n_channel_e_mosfet_transistor_gate_left_drain_top: "n_channel_e_mosfet_transistor_horz",
73118
+ n_channel_e_mosfet_transistor_gate_top_drain_right: "n_channel_e_mosfet_transistor_vert",
73119
+ n_channel_d_mosfet_transistor_gate_left_drain_top: "n_channel_d_mosfet_transistor_horz",
73120
+ n_channel_d_mosfet_transistor_gate_top_drain_right: "n_channel_d_mosfet_transistor_vert",
73121
+ p_channel_e_mosfet_transistor_gate_left_drain_top: "p_channel_e_mosfet_transistor_horz",
73122
+ p_channel_e_mosfet_transistor_gate_top_drain_right: "p_channel_e_mosfet_transistor_vert",
73123
+ p_channel_d_mosfet_transistor_gate_left_drain_top: "p_channel_d_mosfet_transistor_horz",
73124
+ p_channel_d_mosfet_transistor_gate_top_drain_right: "p_channel_d_mosfet_transistor_vert"
73125
+ };
73126
+ var getSchematicSymbolData = (symbolName) => {
73127
+ const resolvedSymbolName = legacySymbolNameByOrientedSymbolName[symbolName] ?? symbolName;
73128
+ return symbols2[resolvedSymbolName];
73129
+ };
73130
+ var normalizePositiveDegrees = (degrees) => (degrees % 360 + 360) % 360;
73131
+ var getDirectedSweepDegrees = ({
73132
+ startAngleDegrees,
73133
+ endAngleDegrees,
73134
+ direction
73135
+ }) => {
73136
+ if (direction === "clockwise") {
73137
+ const sweep2 = normalizePositiveDegrees(startAngleDegrees - endAngleDegrees);
73138
+ return sweep2 === 0 && startAngleDegrees !== endAngleDegrees ? -360 : -sweep2;
73139
+ }
73140
+ const sweep = normalizePositiveDegrees(endAngleDegrees - startAngleDegrees);
73141
+ return sweep === 0 && startAngleDegrees !== endAngleDegrees ? 360 : sweep;
73142
+ };
73143
+ var getPointAtAngle = (arc, angleDegrees) => {
73144
+ const angleRadians = angleDegrees * Math.PI / 180;
73145
+ return {
73146
+ x: arc.center.x + arc.radius * Math.cos(angleRadians),
73147
+ y: arc.center.y + arc.radius * Math.sin(angleRadians)
73148
+ };
73149
+ };
73150
+ var getSchematicArcPoints = (arc) => {
73151
+ const sweepDegrees = getDirectedSweepDegrees({
73152
+ startAngleDegrees: arc.start_angle_degrees,
73153
+ endAngleDegrees: arc.end_angle_degrees,
73154
+ direction: arc.direction
73155
+ });
73156
+ const midAngleDegrees = arc.start_angle_degrees + sweepDegrees / 2;
73157
+ return {
73158
+ start: getPointAtAngle(arc, arc.start_angle_degrees),
73159
+ mid: getPointAtAngle(arc, midAngleDegrees),
73160
+ end: getPointAtAngle(arc, arc.start_angle_degrees + sweepDegrees)
73161
+ };
73162
+ };
72976
73163
  function buildSymbolDataFromSchematicPrimitives(params2) {
72977
73164
  const {
72978
73165
  circuitJson,
@@ -72989,6 +73176,7 @@ function buildSymbolDataFromSchematicPrimitives(params2) {
72989
73176
  }
72990
73177
  return el.schematic_component_id === schematicComponentId && !el.schematic_symbol_id;
72991
73178
  };
73179
+ const arcs = circuitJson.filter((el) => el.type === "schematic_arc" && isElementInTargetSymbolScope(el));
72992
73180
  const circles = circuitJson.filter((el) => el.type === "schematic_circle" && isElementInTargetSymbolScope(el));
72993
73181
  const symbolLines = circuitJson.filter((el) => el.type === "schematic_line" && isElementInTargetSymbolScope(el));
72994
73182
  let schLines = [];
@@ -72997,6 +73185,7 @@ function buildSymbolDataFromSchematicPrimitives(params2) {
72997
73185
  }
72998
73186
  const lines = [...symbolLines, ...schLines];
72999
73187
  const paths = circuitJson.filter((el) => el.type === "schematic_path" && isElementInTargetSymbolScope(el));
73188
+ const rectangles = circuitJson.filter((el) => el.type === "schematic_rect" && isElementInTargetSymbolScope(el));
73000
73189
  const texts = circuitJson.filter((el) => el.type === "schematic_text" && isElementInTargetSymbolScope(el));
73001
73190
  let ports = [];
73002
73191
  if (hasSchematicSymbolId) {
@@ -73030,6 +73219,14 @@ function buildSymbolDataFromSchematicPrimitives(params2) {
73030
73219
  }
73031
73220
  }
73032
73221
  const primitives = [];
73222
+ for (const arc of arcs) {
73223
+ primitives.push({
73224
+ type: "arc",
73225
+ ...getSchematicArcPoints(arc),
73226
+ isDashed: arc.is_dashed,
73227
+ strokeWidth: arc.stroke_width
73228
+ });
73229
+ }
73033
73230
  for (const circle of circles) {
73034
73231
  primitives.push({
73035
73232
  type: "circle",
@@ -73037,7 +73234,8 @@ function buildSymbolDataFromSchematicPrimitives(params2) {
73037
73234
  y: circle.center?.y ?? 0,
73038
73235
  radius: circle.radius ?? 0.5,
73039
73236
  fill: circle.is_filled ?? false,
73040
- fillColor: circle.fill_color
73237
+ fillColor: circle.fill_color,
73238
+ strokeWidth: circle.stroke_width
73041
73239
  });
73042
73240
  }
73043
73241
  for (const line of lines) {
@@ -73046,7 +73244,8 @@ function buildSymbolDataFromSchematicPrimitives(params2) {
73046
73244
  points: [
73047
73245
  { x: line.x1 ?? 0, y: line.y1 ?? 0 },
73048
73246
  { x: line.x2 ?? 0, y: line.y2 ?? 0 }
73049
- ]
73247
+ ],
73248
+ strokeWidth: line.stroke_width
73050
73249
  });
73051
73250
  }
73052
73251
  for (const path of paths) {
@@ -73055,9 +73254,46 @@ function buildSymbolDataFromSchematicPrimitives(params2) {
73055
73254
  type: "path",
73056
73255
  points: path.points,
73057
73256
  fill: path.is_filled ?? false,
73058
- fillColor: path.fill_color
73257
+ fillColor: path.fill_color,
73258
+ strokeWidth: path.stroke_width
73259
+ });
73260
+ }
73261
+ }
73262
+ for (const rect of rectangles) {
73263
+ const halfWidth = rect.width / 2;
73264
+ const halfHeight = rect.height / 2;
73265
+ if ((rect.rotation ?? 0) % 360 === 0) {
73266
+ primitives.push({
73267
+ type: "rectangle",
73268
+ start: { x: rect.center.x - halfWidth, y: rect.center.y - halfHeight },
73269
+ end: { x: rect.center.x + halfWidth, y: rect.center.y + halfHeight },
73270
+ fill: rect.is_filled,
73271
+ fillColor: rect.fill_color,
73272
+ strokeWidth: rect.stroke_width,
73273
+ isDashed: rect.is_dashed
73059
73274
  });
73275
+ continue;
73060
73276
  }
73277
+ const rotationRadians = rect.rotation * Math.PI / 180;
73278
+ const cos = Math.cos(rotationRadians);
73279
+ const sin = Math.sin(rotationRadians);
73280
+ const corners = [
73281
+ { x: -halfWidth, y: -halfHeight },
73282
+ { x: halfWidth, y: -halfHeight },
73283
+ { x: halfWidth, y: halfHeight },
73284
+ { x: -halfWidth, y: halfHeight }
73285
+ ].map((corner) => ({
73286
+ x: rect.center.x + corner.x * cos - corner.y * sin,
73287
+ y: rect.center.y + corner.x * sin + corner.y * cos
73288
+ }));
73289
+ primitives.push({
73290
+ type: "path",
73291
+ points: [...corners, corners[0]],
73292
+ fill: rect.is_filled,
73293
+ fillColor: rect.fill_color,
73294
+ strokeWidth: rect.stroke_width,
73295
+ isDashed: rect.is_dashed
73296
+ });
73061
73297
  }
73062
73298
  const symbolTexts = texts.map((text) => ({
73063
73299
  text: text.text ?? "",
@@ -73083,54 +73319,158 @@ function buildSymbolDataFromSchematicPrimitives(params2) {
73083
73319
  ports: symbolPorts
73084
73320
  };
73085
73321
  }
73322
+ function createArcFromPrimitive({
73323
+ primitive,
73324
+ transform,
73325
+ scale: scale5
73326
+ }) {
73327
+ const start = applyToPoint(transform, primitive.start);
73328
+ const mid = applyToPoint(transform, primitive.mid);
73329
+ const end = applyToPoint(transform, primitive.end);
73330
+ return SymbolArc.fromSexprPrimitives([
73331
+ ["start", start.x, start.y],
73332
+ ["mid", mid.x, mid.y],
73333
+ ["end", end.x, end.y],
73334
+ [
73335
+ "stroke",
73336
+ [
73337
+ "width",
73338
+ primitive.strokeWidth == null ? 0.254 : primitive.strokeWidth * scale5
73339
+ ],
73340
+ ["type", primitive.isDashed ? "dash" : "default"]
73341
+ ],
73342
+ ["fill", ["type", "none"]]
73343
+ ]);
73344
+ }
73345
+ function parseColor(color) {
73346
+ const rgbMatch = color.match(/^rgba?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)(?:\s*,\s*(\d+(?:\.\d+)?))?\s*\)$/i);
73347
+ if (rgbMatch) {
73348
+ return {
73349
+ r: Number(rgbMatch[1]),
73350
+ g: Number(rgbMatch[2]),
73351
+ b: Number(rgbMatch[3]),
73352
+ a: rgbMatch[4] === undefined ? 1 : Number(rgbMatch[4])
73353
+ };
73354
+ }
73355
+ const hexDigits = color.startsWith("#") ? color.slice(1) : color;
73356
+ if (![3, 4, 6, 8].includes(hexDigits.length))
73357
+ return;
73358
+ if (!/^[0-9a-f]+$/i.test(hexDigits))
73359
+ return;
73360
+ const expandedHexDigits = hexDigits.length <= 4 ? [...hexDigits].map((digit) => `${digit}${digit}`).join("") : hexDigits;
73361
+ return {
73362
+ r: Number.parseInt(expandedHexDigits.slice(0, 2), 16),
73363
+ g: Number.parseInt(expandedHexDigits.slice(2, 4), 16),
73364
+ b: Number.parseInt(expandedHexDigits.slice(4, 6), 16),
73365
+ a: expandedHexDigits.length === 8 ? Number.parseInt(expandedHexDigits.slice(6, 8), 16) / 255 : 1
73366
+ };
73367
+ }
73368
+ function createSymbolFillSexprPrimitives({
73369
+ isFilled,
73370
+ fillColor,
73371
+ fallbackFillType = "background"
73372
+ }) {
73373
+ if (!isFilled)
73374
+ return [["type", "none"]];
73375
+ const parsedFillColor = fillColor ? parseColor(fillColor) : undefined;
73376
+ if (!parsedFillColor)
73377
+ return [["type", fallbackFillType]];
73378
+ return [
73379
+ ["type", "color"],
73380
+ [
73381
+ "color",
73382
+ parsedFillColor.r,
73383
+ parsedFillColor.g,
73384
+ parsedFillColor.b,
73385
+ parsedFillColor.a
73386
+ ]
73387
+ ];
73388
+ }
73389
+ function createCircleFromPrimitive({
73390
+ primitive,
73391
+ transform,
73392
+ scale: scale5
73393
+ }) {
73394
+ const scaledPos = applyToPoint2(transform, {
73395
+ x: primitive.x,
73396
+ y: primitive.y
73397
+ });
73398
+ return SymbolCircle.fromSexprPrimitives([
73399
+ ["center", scaledPos.x, scaledPos.y],
73400
+ ["radius", primitive.radius * scale5],
73401
+ [
73402
+ "stroke",
73403
+ [
73404
+ "width",
73405
+ primitive.strokeWidth == null ? 0.254 : primitive.strokeWidth * scale5
73406
+ ],
73407
+ ["type", "default"]
73408
+ ],
73409
+ [
73410
+ "fill",
73411
+ ...createSymbolFillSexprPrimitives({
73412
+ isFilled: primitive.fill ?? false,
73413
+ fillColor: primitive.fillColor,
73414
+ fallbackFillType: primitive.kicadFillType === "outline" ? "outline" : "background"
73415
+ })
73416
+ ]
73417
+ ]);
73418
+ }
73086
73419
  function createPolylineFromPoints({
73087
73420
  points,
73088
73421
  transform,
73089
- fillType
73422
+ isFilled,
73423
+ fillColor,
73424
+ fallbackFillType,
73425
+ strokeWidth,
73426
+ isDashed,
73427
+ scale: scale5
73090
73428
  }) {
73091
73429
  const polyline = new SymbolPolyline;
73092
73430
  const xyPoints = points.map((p) => {
73093
- const transformed = applyToPoint(transform, p);
73431
+ const transformed = applyToPoint3(transform, p);
73094
73432
  return new Xy(transformed.x, transformed.y);
73095
73433
  });
73096
73434
  const pts = new Pts(xyPoints);
73097
73435
  polyline.points = pts;
73098
73436
  const stroke = new Stroke2;
73099
- stroke.width = 0.254;
73100
- stroke.type = "default";
73437
+ stroke.width = strokeWidth == null ? 0.254 : strokeWidth * scale5;
73438
+ stroke.type = isDashed ? "dash" : "default";
73101
73439
  polyline.stroke = stroke;
73102
- const fill = new SymbolPolylineFill;
73103
- fill.type = fillType;
73440
+ const fill = SymbolPolylineFill.fromSexprPrimitives(createSymbolFillSexprPrimitives({
73441
+ isFilled,
73442
+ fillColor,
73443
+ fallbackFillType
73444
+ }));
73104
73445
  polyline.fill = fill;
73105
73446
  return polyline;
73106
73447
  }
73107
- function createCircleFromPrimitive({
73448
+ function createRectangleFromPrimitive({
73108
73449
  primitive,
73109
73450
  transform,
73110
73451
  scale: scale5
73111
73452
  }) {
73112
- const circle = new SymbolCircle;
73113
- const scaledPos = applyToPoint2(transform, {
73114
- x: primitive.x,
73115
- y: primitive.y
73116
- });
73117
- const c = circle;
73118
- c._sxCenter = new SymbolCircleCenter(scaledPos.x, scaledPos.y);
73119
- c._sxRadius = new SymbolCircleRadius(primitive.radius * scale5);
73120
- const stroke = new Stroke3;
73121
- stroke.width = 0.254;
73122
- stroke.type = "default";
73123
- c._sxStroke = stroke;
73124
- const fill = new SymbolCircleFill;
73125
- fill.type = "none";
73126
- if (primitive.fill) {
73127
- fill.type = "background";
73128
- if (primitive.kicadFillType === "outline") {
73129
- fill.type = "outline";
73130
- }
73131
- }
73132
- c._sxFill = fill;
73133
- return circle;
73453
+ const start = applyToPoint4(transform, primitive.start);
73454
+ const end = applyToPoint4(transform, primitive.end);
73455
+ return SymbolRectangle.fromSexprPrimitives([
73456
+ ["start", start.x, start.y],
73457
+ ["end", end.x, end.y],
73458
+ [
73459
+ "stroke",
73460
+ [
73461
+ "width",
73462
+ primitive.strokeWidth == null ? 0.254 : primitive.strokeWidth * scale5
73463
+ ],
73464
+ ["type", primitive.isDashed ? "dash" : "default"]
73465
+ ],
73466
+ [
73467
+ "fill",
73468
+ ...createSymbolFillSexprPrimitives({
73469
+ isFilled: primitive.fill ?? false,
73470
+ fillColor: primitive.fillColor
73471
+ })
73472
+ ]
73473
+ ]);
73134
73474
  }
73135
73475
  function createTextFromPrimitive({
73136
73476
  schText,
@@ -73138,7 +73478,7 @@ function createTextFromPrimitive({
73138
73478
  scale: scale5
73139
73479
  }) {
73140
73480
  const symbolText = new SymbolText;
73141
- const scaledPos = applyToPoint3(transform, { x: schText.x, y: schText.y });
73481
+ const scaledPos = applyToPoint5(transform, { x: schText.x, y: schText.y });
73142
73482
  symbolText.value = schText.text;
73143
73483
  symbolText.at = [scaledPos.x, scaledPos.y, 0];
73144
73484
  const scaledFontSize = schText.fontSize * scale5;
@@ -73161,20 +73501,30 @@ function createDrawingSubsymbol({
73161
73501
  const cy = symbolData.center?.y ?? 0;
73162
73502
  const transform = compose(createScaleMatrix(symbolScale, symbolScale), translate(-cx, -cy));
73163
73503
  for (const primitive of symbolData.primitives || []) {
73164
- if (primitive.type === "path" && primitive.points) {
73165
- let fillType = "none";
73166
- if (primitive.fill) {
73167
- fillType = "background";
73168
- if (primitive.kicadFillType === "outline") {
73169
- fillType = "outline";
73170
- }
73171
- }
73504
+ if (primitive.type === "arc") {
73505
+ drawingSymbol.arcs.push(createArcFromPrimitive({
73506
+ primitive,
73507
+ transform,
73508
+ scale: symbolScale
73509
+ }));
73510
+ } else if (primitive.type === "path" && primitive.points) {
73172
73511
  const polyline = createPolylineFromPoints({
73173
73512
  points: primitive.points,
73174
73513
  transform,
73175
- fillType
73514
+ isFilled: primitive.fill ?? false,
73515
+ fillColor: primitive.fillColor,
73516
+ fallbackFillType: primitive.kicadFillType === "outline" ? "outline" : "background",
73517
+ strokeWidth: primitive.strokeWidth,
73518
+ isDashed: primitive.isDashed,
73519
+ scale: symbolScale
73176
73520
  });
73177
73521
  drawingSymbol.polylines.push(polyline);
73522
+ } else if (primitive.type === "rectangle") {
73523
+ drawingSymbol.rectangles.push(createRectangleFromPrimitive({
73524
+ primitive,
73525
+ transform,
73526
+ scale: symbolScale
73527
+ }));
73178
73528
  } else if (primitive.type === "circle") {
73179
73529
  const circle = createCircleFromPrimitive({
73180
73530
  primitive,
@@ -73335,7 +73685,7 @@ function calculatePinPosition({
73335
73685
  dy = portY - cy;
73336
73686
  }
73337
73687
  const scaleMatrix = createScaleMatrix2(symbolScale, symbolScale);
73338
- const scaled = applyToPoint4(scaleMatrix, { x: dx, y: dy });
73688
+ const scaled = applyToPoint6(scaleMatrix, { x: dx, y: dy });
73339
73689
  let isHorizontalPin;
73340
73690
  if (isChip && size) {
73341
73691
  const halfWidth = size.width / 2;
@@ -73477,7 +73827,7 @@ var AddLibrarySymbolsStage = class extends ConverterStage {
73477
73827
  const cadComponent = db.cad_component?.list()?.find((cad) => cad.source_component_id === sourceComp.source_component_id);
73478
73828
  let schematicSymbolId = schematicComponent.schematic_symbol_id;
73479
73829
  if (!schematicSymbolId) {
73480
- const linkedPrimitive = this.ctx.circuitJson.find((el) => (el.type === "schematic_line" || el.type === "schematic_circle" || el.type === "schematic_path") && el.schematic_component_id === schematicComponent.schematic_component_id && el.schematic_symbol_id);
73830
+ const linkedPrimitive = this.ctx.circuitJson.find((el) => (el.type === "schematic_line" || el.type === "schematic_circle" || el.type === "schematic_arc" || el.type === "schematic_path" || el.type === "schematic_rect") && el.schematic_component_id === schematicComponent.schematic_component_id && el.schematic_symbol_id);
73481
73831
  if (linkedPrimitive) {
73482
73832
  schematicSymbolId = linkedPrimitive.schematic_symbol_id;
73483
73833
  }
@@ -73485,7 +73835,7 @@ var AddLibrarySymbolsStage = class extends ConverterStage {
73485
73835
  if (schematicSymbolId) {
73486
73836
  return this.createLibrarySymbolFromSchematicSymbol(schematicComponent, sourceComp, cadComponent, schematicSymbolId);
73487
73837
  }
73488
- const hasInnerSymbolPrimitives = this.hasComponentLevelSymbolPrimitives(schematicComponent.schematic_component_id);
73838
+ const hasInnerSymbolPrimitives = hasComponentLevelSymbolPrimitives(this.ctx.circuitJson, schematicComponent);
73489
73839
  if (hasInnerSymbolPrimitives) {
73490
73840
  const innerSymbolData = buildSymbolDataFromSchematicPrimitives({
73491
73841
  circuitJson: this.ctx.circuitJson,
@@ -73498,22 +73848,11 @@ var AddLibrarySymbolsStage = class extends ConverterStage {
73498
73848
  }
73499
73849
  });
73500
73850
  if (innerSymbolData.primitives?.length > 0) {
73501
- const baseSymbolData = createGenericChipSymbolData(schematicComponent, this.ctx.db);
73502
- const innerPrimitivesWithFillHints = (innerSymbolData.primitives || []).map((primitive) => {
73503
- if (primitive.fill && primitive.fillColor) {
73504
- return { ...primitive, kicadFillType: "outline" };
73505
- }
73506
- return primitive;
73507
- });
73508
73851
  const symbolData2 = {
73509
- ...baseSymbolData,
73510
- primitives: [
73511
- ...baseSymbolData.primitives || [],
73512
- ...innerPrimitivesWithFillHints
73513
- ],
73852
+ ...innerSymbolData,
73514
73853
  texts: []
73515
73854
  };
73516
- const libId2 = getLibraryId(sourceComp, schematicComponent, cadComponent);
73855
+ const libId2 = getComponentLevelLibraryId(sourceComp, schematicComponent, cadComponent);
73517
73856
  const footprintName2 = getKicadCompatibleComponentName(sourceComp, cadComponent);
73518
73857
  let footprintRef = "";
73519
73858
  if (footprintName2) {
@@ -73522,7 +73861,8 @@ var AddLibrarySymbolsStage = class extends ConverterStage {
73522
73861
  return this.createLibrarySymbol({
73523
73862
  libId: libId2,
73524
73863
  symbolData: symbolData2,
73525
- isChip: true,
73864
+ isChip: false,
73865
+ hidePinNames: true,
73526
73866
  schematicComponent,
73527
73867
  description: this.getDescription(sourceComp),
73528
73868
  keywords: this.getKeywords(sourceComp),
@@ -73565,12 +73905,7 @@ var AddLibrarySymbolsStage = class extends ConverterStage {
73565
73905
  if (schematicSymbol.name) {
73566
73906
  symbolName = schematicSymbol.name;
73567
73907
  } else {
73568
- const ergonomicName = getKicadCompatibleComponentName(sourceComp, cadComponent);
73569
- if (ergonomicName) {
73570
- symbolName = ergonomicName;
73571
- } else {
73572
- symbolName = `custom_${sourceComp.ftype || "component"}_${schematicSymbolId}`;
73573
- }
73908
+ symbolName = getKicadCompatibleCustomSymbolName(sourceComp, cadComponent, schematicSymbolId);
73574
73909
  }
73575
73910
  const libId = `Custom:${symbolName}`;
73576
73911
  if (this.processedSymbolNames.has(libId)) {
@@ -73607,7 +73942,7 @@ var AddLibrarySymbolsStage = class extends ConverterStage {
73607
73942
  const symbolName = netLabel.symbol_name;
73608
73943
  if (!symbolName)
73609
73944
  return null;
73610
- const symbolData = symbols2[symbolName];
73945
+ const symbolData = symbols3[symbolName];
73611
73946
  if (!symbolData)
73612
73947
  return null;
73613
73948
  const libId = `Custom:${symbolName}`;
@@ -73627,12 +73962,13 @@ var AddLibrarySymbolsStage = class extends ConverterStage {
73627
73962
  if (symbolName.startsWith("generic_chip_")) {
73628
73963
  return createGenericChipSymbolData(schematicComponent, this.ctx.db);
73629
73964
  }
73630
- return symbols2[symbolName] || null;
73965
+ return getSchematicSymbolData(symbolName) || null;
73631
73966
  }
73632
73967
  createLibrarySymbol({
73633
73968
  libId,
73634
73969
  symbolData,
73635
73970
  isChip,
73971
+ hidePinNames = false,
73636
73972
  schematicComponent,
73637
73973
  description,
73638
73974
  keywords,
@@ -73652,6 +73988,8 @@ var AddLibrarySymbolsStage = class extends ConverterStage {
73652
73988
  symbol._sxPinNumbers = pinNumbers;
73653
73989
  const pinNames = new SymbolPinNames;
73654
73990
  pinNames.offset = isChip ? 1.27 : 0;
73991
+ if (hidePinNames)
73992
+ pinNames.hide = true;
73655
73993
  symbol._sxPinNames = pinNames;
73656
73994
  addSymbolProperties({
73657
73995
  symbol,
@@ -73717,11 +74055,6 @@ var AddLibrarySymbolsStage = class extends ConverterStage {
73717
74055
  return "*";
73718
74056
  return "*";
73719
74057
  }
73720
- hasComponentLevelSymbolPrimitives(schematicComponentId) {
73721
- if (!schematicComponentId)
73722
- return false;
73723
- return this.ctx.circuitJson.some((el) => (el.type === "schematic_path" || el.type === "schematic_circle" || el.type === "schematic_line" || el.type === "schematic_text") && el.schematic_component_id === schematicComponentId && !el.schematic_symbol_id);
73724
- }
73725
74058
  getOutput() {
73726
74059
  if (!this.ctx.kicadSch) {
73727
74060
  throw new Error("kicadSch is not initialized");
@@ -73771,7 +74104,7 @@ var DEFAULT_SECTION_LINE_COLOR = { r: 0, g: 0, b: 0, a: 1 };
73771
74104
  var DEFAULT_SECTION_TEXT_COLOR = { r: 0, g: 0, b: 0, a: 1 };
73772
74105
  var DEFAULT_SECTION_TEXT_PADDING_X_MM = 0.22;
73773
74106
  var DEFAULT_SECTION_TEXT_PADDING_Y_MM = 0.18;
73774
- var isStandaloneSchematicElement = (element) => !element.schematic_component_id;
74107
+ var isStandaloneSchematicElement = (element) => !element.schematic_component_id && !(("schematic_symbol_id" in element) && element.schematic_symbol_id);
73775
74108
  var AddSchematicGraphicsStage = class extends ConverterStage {
73776
74109
  _step() {
73777
74110
  const { kicadSch, db } = this.ctx;
@@ -73783,19 +74116,47 @@ var AddSchematicGraphicsStage = class extends ConverterStage {
73783
74116
  return;
73784
74117
  }
73785
74118
  const schematicLines = (db.schematic_line?.list() || []).filter(isStandaloneSchematicElement);
74119
+ const schematicArcs = (db.schematic_arc?.list() || []).filter(isStandaloneSchematicElement);
73786
74120
  const schematicTexts = (db.schematic_text?.list() || []).filter(isStandaloneSchematicElement);
73787
- if (schematicLines.length === 0 && schematicTexts.length === 0) {
74121
+ const preserveStandaloneGraphics = db.schematic_component.list().some((component) => hasComponentLevelSymbolPrimitives(this.ctx.circuitJson, component));
74122
+ const schematicRects = preserveStandaloneGraphics ? (db.schematic_rect?.list() || []).filter(isStandaloneSchematicElement) : [];
74123
+ const schematicPaths = preserveStandaloneGraphics ? (db.schematic_path?.list() || []).filter(isStandaloneSchematicElement) : [];
74124
+ if (schematicLines.length === 0 && schematicArcs.length === 0 && schematicTexts.length === 0 && schematicRects.length === 0 && schematicPaths.length === 0) {
73788
74125
  this.finished = true;
73789
74126
  return;
73790
74127
  }
74128
+ if (schematicArcs.length > 0) {
74129
+ const arcs = kicadSch.arcs || [];
74130
+ for (const arc of schematicArcs) {
74131
+ const points = getSchematicArcPoints(arc);
74132
+ const start = applyToPoint7(this.ctx.c2kMatSch, points.start);
74133
+ const mid = applyToPoint7(this.ctx.c2kMatSch, points.mid);
74134
+ const end = applyToPoint7(this.ctx.c2kMatSch, points.end);
74135
+ const stroke = new Stroke3;
74136
+ stroke.width = (arc.stroke_width ?? 0) * (this.ctx.kicadSchematicScaleFactor ?? 1);
74137
+ stroke.type = arc.is_dashed ? "dash" : "default";
74138
+ stroke.color = preserveStandaloneGraphics ? parseColor(arc.color) ?? DEFAULT_SECTION_LINE_COLOR : DEFAULT_SECTION_LINE_COLOR;
74139
+ const fill = new SymbolArcFill;
74140
+ fill.type = "none";
74141
+ arcs.push(new SchematicArc({
74142
+ start,
74143
+ mid,
74144
+ end,
74145
+ stroke,
74146
+ fill,
74147
+ uuid: crypto.randomUUID()
74148
+ }));
74149
+ }
74150
+ kicadSch.arcs = arcs;
74151
+ }
73791
74152
  if (schematicLines.length > 0) {
73792
74153
  const polylines = kicadSch.polylines || [];
73793
74154
  for (const line of schematicLines) {
73794
- const start = applyToPoint5(this.ctx.c2kMatSch, {
74155
+ const start = applyToPoint7(this.ctx.c2kMatSch, {
73795
74156
  x: line.x1,
73796
74157
  y: line.y1
73797
74158
  });
73798
- const end = applyToPoint5(this.ctx.c2kMatSch, {
74159
+ const end = applyToPoint7(this.ctx.c2kMatSch, {
73799
74160
  x: line.x2,
73800
74161
  y: line.y2
73801
74162
  });
@@ -73804,35 +74165,92 @@ var AddSchematicGraphicsStage = class extends ConverterStage {
73804
74165
  new Xy2(start.x, start.y),
73805
74166
  new Xy2(end.x, end.y)
73806
74167
  ]);
73807
- const stroke = new Stroke4;
74168
+ const stroke = new Stroke3;
73808
74169
  stroke.width = 0;
73809
74170
  stroke.type = "default";
73810
- stroke.color = DEFAULT_SECTION_LINE_COLOR;
74171
+ stroke.color = preserveStandaloneGraphics ? parseColor(line.color) ?? DEFAULT_SECTION_LINE_COLOR : DEFAULT_SECTION_LINE_COLOR;
73811
74172
  polyline.stroke = stroke;
73812
74173
  polyline.uuid = new Uuid(crypto.randomUUID());
73813
74174
  polylines.push(polyline);
73814
74175
  }
73815
74176
  kicadSch.polylines = polylines;
73816
74177
  }
74178
+ if (schematicPaths.length > 0) {
74179
+ const polylines = kicadSch.polylines || [];
74180
+ for (const path of schematicPaths) {
74181
+ if (path.points.length < 2)
74182
+ continue;
74183
+ const stroke = new Stroke3;
74184
+ stroke.width = (path.stroke_width ?? 0) * (this.ctx.kicadSchematicScaleFactor ?? 1);
74185
+ stroke.type = path.is_dashed ? "dash" : "default";
74186
+ stroke.color = preserveStandaloneGraphics ? parseColor(path.stroke_color ?? "") ?? DEFAULT_SECTION_LINE_COLOR : DEFAULT_SECTION_LINE_COLOR;
74187
+ polylines.push(new Polyline({
74188
+ points: new Pts2(path.points.map((point) => {
74189
+ const transformed = applyToPoint7(this.ctx.c2kMatSch, point);
74190
+ return new Xy2(transformed.x, transformed.y);
74191
+ })),
74192
+ stroke,
74193
+ uuid: crypto.randomUUID()
74194
+ }));
74195
+ }
74196
+ kicadSch.polylines = polylines;
74197
+ }
74198
+ if (schematicRects.length > 0) {
74199
+ const rectangles = kicadSch.rectangles || [];
74200
+ for (const rect of schematicRects) {
74201
+ const halfWidth = rect.width / 2;
74202
+ const halfHeight = rect.height / 2;
74203
+ const firstCorner = applyToPoint7(this.ctx.c2kMatSch, {
74204
+ x: rect.center.x - halfWidth,
74205
+ y: rect.center.y - halfHeight
74206
+ });
74207
+ const secondCorner = applyToPoint7(this.ctx.c2kMatSch, {
74208
+ x: rect.center.x + halfWidth,
74209
+ y: rect.center.y + halfHeight
74210
+ });
74211
+ const stroke = new Stroke3;
74212
+ stroke.width = (rect.stroke_width ?? 0) * (this.ctx.kicadSchematicScaleFactor ?? 1);
74213
+ stroke.type = rect.is_dashed ? "dash" : "default";
74214
+ stroke.color = preserveStandaloneGraphics ? parseColor(rect.color) ?? DEFAULT_SECTION_LINE_COLOR : DEFAULT_SECTION_LINE_COLOR;
74215
+ const fill = new SymbolRectangleFill;
74216
+ const fillColor = rect.fill_color ? parseColor(rect.fill_color) : undefined;
74217
+ fill.type = rect.is_filled ? fillColor ? "color" : "background" : "none";
74218
+ if (fillColor)
74219
+ fill.color = fillColor;
74220
+ rectangles.push(new SchematicRectangle({
74221
+ start: {
74222
+ x: Math.min(firstCorner.x, secondCorner.x),
74223
+ y: Math.min(firstCorner.y, secondCorner.y)
74224
+ },
74225
+ end: {
74226
+ x: Math.max(firstCorner.x, secondCorner.x),
74227
+ y: Math.max(firstCorner.y, secondCorner.y)
74228
+ },
74229
+ stroke,
74230
+ fill,
74231
+ uuid: crypto.randomUUID()
74232
+ }));
74233
+ }
74234
+ kicadSch.rectangles = rectangles;
74235
+ }
73817
74236
  if (schematicTexts.length > 0) {
73818
74237
  const texts = kicadSch.texts || [];
73819
74238
  for (const text of schematicTexts) {
73820
74239
  const isInlineTraceText = "source_trace_id" in text;
74240
+ const preserveText = preserveStandaloneGraphics && !isInlineTraceText;
73821
74241
  let sourceY = text.position?.y ?? 0;
73822
- if (!isInlineTraceText && text.position?.y !== undefined && text.position.y < 2) {
74242
+ if (!isInlineTraceText && !preserveText && text.position?.y !== undefined && text.position.y < 2) {
73823
74243
  sourceY = text.position.y - DEFAULT_SECTION_TEXT_PADDING_Y_MM;
73824
74244
  }
73825
- const position = applyToPoint5(this.ctx.c2kMatSch, {
73826
- x: (text.position?.x ?? 0) + (isInlineTraceText ? 0 : DEFAULT_SECTION_TEXT_PADDING_X_MM),
74245
+ const position = applyToPoint7(this.ctx.c2kMatSch, {
74246
+ x: (text.position?.x ?? 0) + (isInlineTraceText || preserveText ? 0 : DEFAULT_SECTION_TEXT_PADDING_X_MM),
73827
74247
  y: sourceY
73828
74248
  });
73829
74249
  const font = new TextEffectsFont5;
73830
- font.size = {
73831
- height: DEFAULT_SECTION_TEXT_SIZE_MM,
73832
- width: DEFAULT_SECTION_TEXT_SIZE_MM
73833
- };
73834
- font.color = DEFAULT_SECTION_TEXT_COLOR;
73835
- const justify = isInlineTraceText ? getTextJustificationFromAnchor(text.anchor) : undefined;
74250
+ const fontSize = preserveText ? Math.max(0.01, text.font_size * (this.ctx.kicadSchematicScaleFactor ?? 1)) : DEFAULT_SECTION_TEXT_SIZE_MM;
74251
+ font.size = { height: fontSize, width: fontSize };
74252
+ font.color = preserveText ? parseColor(text.color) ?? DEFAULT_SECTION_TEXT_COLOR : DEFAULT_SECTION_TEXT_COLOR;
74253
+ const justify = isInlineTraceText || preserveText ? getTextJustificationFromAnchor(text.anchor) : undefined;
73836
74254
  const effects = new TextEffects5({
73837
74255
  font,
73838
74256
  hiddenText: false,
@@ -73903,9 +74321,9 @@ var AddSchematicNetLabelsStage = class extends ConverterStage {
73903
74321
  x: netLabel.anchor_position?.x ?? netLabel.center?.x ?? 0,
73904
74322
  y: netLabel.anchor_position?.y ?? netLabel.center?.y ?? 0
73905
74323
  };
73906
- const anchorInKicad = applyToPoint6(this.ctx.c2kMatSch, anchorPoint);
74324
+ const anchorInKicad = applyToPoint8(this.ctx.c2kMatSch, anchorPoint);
73907
74325
  let { x, y } = anchorInKicad;
73908
- const symbolData = symbols3[symbolName];
74326
+ const symbolData = symbols4[symbolName];
73909
74327
  const port = symbolData?.ports?.[0];
73910
74328
  if (port) {
73911
74329
  const pinPosition = calculatePinPosition({
@@ -73991,7 +74409,7 @@ var AddSchematicNetLabelsStage = class extends ConverterStage {
73991
74409
  createGlobalLabel(netLabel, labelText) {
73992
74410
  if (!this.ctx.c2kMatSch || !this.ctx.kicadSch)
73993
74411
  return null;
73994
- const { x, y } = applyToPoint6(this.ctx.c2kMatSch, {
74412
+ const { x, y } = applyToPoint8(this.ctx.c2kMatSch, {
73995
74413
  x: netLabel.anchor_position?.x ?? netLabel.center?.x ?? 0,
73996
74414
  y: netLabel.anchor_position?.y ?? netLabel.center?.y ?? 0
73997
74415
  });
@@ -74063,7 +74481,7 @@ var AddSchematicSymbolsStage = class extends ConverterStage {
74063
74481
  continue;
74064
74482
  if (!this.ctx.c2kMatSch)
74065
74483
  continue;
74066
- const { x, y } = applyToPoint7(this.ctx.c2kMatSch, {
74484
+ const { x, y } = applyToPoint9(this.ctx.c2kMatSch, {
74067
74485
  x: schematicComponent.center.x,
74068
74486
  y: schematicComponent.center.y
74069
74487
  });
@@ -74082,7 +74500,7 @@ var AddSchematicSymbolsStage = class extends ConverterStage {
74082
74500
  let schematicSymbolName;
74083
74501
  let schematicSymbolId = schematicComponent.schematic_symbol_id;
74084
74502
  if (!schematicSymbolId) {
74085
- const linkedPrimitive = this.ctx.circuitJson.find((el) => (el.type === "schematic_line" || el.type === "schematic_circle" || el.type === "schematic_path") && el.schematic_component_id === schematicComponent.schematic_component_id && el.schematic_symbol_id);
74503
+ const linkedPrimitive = this.ctx.circuitJson.find((el) => (el.type === "schematic_line" || el.type === "schematic_circle" || el.type === "schematic_arc" || el.type === "schematic_path" || el.type === "schematic_rect") && el.schematic_component_id === schematicComponent.schematic_component_id && el.schematic_symbol_id);
74086
74504
  if (linkedPrimitive) {
74087
74505
  schematicSymbolId = linkedPrimitive.schematic_symbol_id;
74088
74506
  }
@@ -74092,15 +74510,11 @@ var AddSchematicSymbolsStage = class extends ConverterStage {
74092
74510
  if (schematicSymbol?.name) {
74093
74511
  schematicSymbolName = schematicSymbol.name;
74094
74512
  } else {
74095
- const ergonomicName = getKicadCompatibleComponentName(sourceComponent, cadComponent);
74096
- if (ergonomicName) {
74097
- schematicSymbolName = ergonomicName;
74098
- } else {
74099
- schematicSymbolName = `custom_${sourceComponent.ftype || "component"}_${schematicSymbolId}`;
74100
- }
74513
+ schematicSymbolName = getKicadCompatibleCustomSymbolName(sourceComponent, cadComponent, schematicSymbolId);
74101
74514
  }
74102
74515
  }
74103
- const libId = getLibraryId(sourceComponent, schematicComponent, cadComponent, schematicSymbolName);
74516
+ const usesComponentLevelSymbolPrimitives = hasComponentLevelSymbolPrimitives(this.ctx.circuitJson, schematicComponent);
74517
+ const libId = usesComponentLevelSymbolPrimitives ? getComponentLevelLibraryId(sourceComponent, schematicComponent, cadComponent) : getLibraryId(sourceComponent, schematicComponent, cadComponent, schematicSymbolName);
74104
74518
  const symLibId = new SymbolLibId2(libId);
74105
74519
  symbol._sxLibId = symLibId;
74106
74520
  const { reference, value, description } = this.getComponentMetadata(sourceComponent);
@@ -74119,14 +74533,18 @@ var AddSchematicSymbolsStage = class extends ConverterStage {
74119
74533
  }
74120
74534
  }
74121
74535
  const refMeta = symbolMetadata?.properties?.Reference;
74536
+ const hideGeneratedCustomReference = Boolean(schematicSymbolId) || usesComponentLevelSymbolPrimitives;
74122
74537
  const referenceProperty = new SymbolProperty3({
74123
74538
  key: "Reference",
74124
74539
  value: refMeta?.value ?? reference,
74125
74540
  id: 0,
74126
74541
  at: [refTextPos.x, refTextPos.y, 0],
74127
- effects: this.createTextEffects(Number(refMeta?.effects?.font?.size?.x ?? 1.27), { hide: refMeta?.effects?.hide ?? false, justify: refJustify })
74542
+ effects: this.createTextEffects(Number(refMeta?.effects?.font?.size?.x ?? 1.27), {
74543
+ hide: refMeta?.effects?.hide ?? hideGeneratedCustomReference,
74544
+ justify: refJustify
74545
+ })
74128
74546
  });
74129
- const hideValue = sourceComponent.ftype === "simple_chip" && !hasManufacturerValueForValuePlacement || sourceComponent.ftype === "simple_pin_header" || sourceComponent.ftype === "simple_test_point";
74547
+ const hideValue = Boolean(schematicSymbolId) || usesComponentLevelSymbolPrimitives || sourceComponent.ftype === "simple_chip" && !hasManufacturerValueForValuePlacement || sourceComponent.ftype === "simple_diode" && !schematicComponent.symbol_display_value || sourceComponent.ftype === "simple_pin_header" || sourceComponent.ftype === "simple_test_point";
74130
74548
  const valMeta = symbolMetadata?.properties?.Value;
74131
74549
  const valueProperty = new SymbolProperty3({
74132
74550
  key: "Value",
@@ -74263,11 +74681,11 @@ var AddSchematicSymbolsStage = class extends ConverterStage {
74263
74681
  value
74264
74682
  }) {
74265
74683
  const c2kMatSch = this.ctx.c2kMatSch;
74266
- const symbolKicadPos = applyToPoint7(c2kMatSch, {
74684
+ const symbolKicadPos = applyToPoint9(c2kMatSch, {
74267
74685
  x: schematicComponent.center.x,
74268
74686
  y: schematicComponent.center.y
74269
74687
  });
74270
- const bodyEdge = applyToPoint7(c2kMatSch, {
74688
+ const bodyEdge = applyToPoint9(c2kMatSch, {
74271
74689
  x: schematicComponent.center.x,
74272
74690
  y: schematicComponent.center.y + (schematicComponent.size?.height || 1) / 2
74273
74691
  });
@@ -74332,7 +74750,7 @@ var AddSchematicSymbolsStage = class extends ConverterStage {
74332
74750
  valTextPos: { x: symbolKicadPos.x, y: valueBelowBodyY }
74333
74751
  };
74334
74752
  }
74335
- const symbol = symbols4[symbolName];
74753
+ const symbol = getSchematicSymbolData(symbolName);
74336
74754
  if (!symbol) {
74337
74755
  return {
74338
74756
  refTextPos: { x: symbolKicadPos.x, y: referenceAboveBodyY },
@@ -74351,29 +74769,26 @@ var AddSchematicSymbolsStage = class extends ConverterStage {
74351
74769
  }
74352
74770
  }
74353
74771
  const symbolCenter = symbol.center || { x: 0, y: 0 };
74354
- const isVertical = symbolName.includes("_down") || symbolName.includes("_up");
74355
- const horizontalTextOffset = isVertical ? 0.15 : 0;
74356
- const refTextPos = refTextPrimitive ? applyToPoint7(c2kMatSch, {
74357
- x: schematicComponent.center.x + (refTextPrimitive.x - symbolCenter.x) + horizontalTextOffset,
74772
+ const refTextPos = refTextPrimitive ? applyToPoint9(c2kMatSch, {
74773
+ x: schematicComponent.center.x + (refTextPrimitive.x - symbolCenter.x),
74358
74774
  y: schematicComponent.center.y + (refTextPrimitive.y - symbolCenter.y)
74359
74775
  }) : { x: symbolKicadPos.x, y: referenceAboveBodyY };
74360
- const valTextPos = valTextPrimitive ? applyToPoint7(c2kMatSch, {
74361
- x: schematicComponent.center.x + (valTextPrimitive.x - symbolCenter.x) + horizontalTextOffset,
74776
+ const valTextPos = valTextPrimitive ? applyToPoint9(c2kMatSch, {
74777
+ x: schematicComponent.center.x + (valTextPrimitive.x - symbolCenter.x),
74362
74778
  y: schematicComponent.center.y + (valTextPrimitive.y - symbolCenter.y)
74363
74779
  }) : { x: symbolKicadPos.x, y: valueBelowBodyY };
74364
- const shouldPreservePrimitiveAnchors = symbolName.startsWith("testpoint_");
74365
74780
  return {
74366
74781
  refTextPos,
74367
74782
  valTextPos,
74368
- refJustify: shouldPreservePrimitiveAnchors ? getTextJustificationFromAnchor(refTextPrimitive?.anchor) : undefined,
74369
- valJustify: shouldPreservePrimitiveAnchors ? getTextJustificationFromAnchor(valTextPrimitive?.anchor) : undefined
74783
+ refJustify: getTextJustificationFromAnchor(refTextPrimitive?.anchor),
74784
+ valJustify: getTextJustificationFromAnchor(valTextPrimitive?.anchor)
74370
74785
  };
74371
74786
  }
74372
74787
  getTextPosition(text) {
74373
74788
  if (!text)
74374
74789
  return;
74375
74790
  return {
74376
- position: applyToPoint7(this.ctx.c2kMatSch, text.position),
74791
+ position: applyToPoint9(this.ctx.c2kMatSch, text.position),
74377
74792
  justify: getTextJustificationFromAnchor(text.anchor)
74378
74793
  };
74379
74794
  }
@@ -74381,7 +74796,7 @@ var AddSchematicSymbolsStage = class extends ConverterStage {
74381
74796
  const componentId = schematicComponent.schematic_component_id;
74382
74797
  if (!componentId)
74383
74798
  return false;
74384
- return this.ctx.circuitJson.some((el) => (el.type === "schematic_line" || el.type === "schematic_circle" || el.type === "schematic_path") && el.schematic_component_id === componentId && el.schematic_symbol_id);
74799
+ return this.ctx.circuitJson.some((el) => (el.type === "schematic_line" || el.type === "schematic_circle" || el.type === "schematic_arc" || el.type === "schematic_path" || el.type === "schematic_rect") && el.schematic_component_id === componentId && el.schematic_symbol_id);
74385
74800
  }
74386
74801
  getComponentMetadata(sourceComp) {
74387
74802
  const name = sourceComp.name || "?";
@@ -74419,7 +74834,7 @@ var AddSchematicSymbolsStage = class extends ConverterStage {
74419
74834
  if (sourceComp.ftype === "simple_diode") {
74420
74835
  return {
74421
74836
  reference,
74422
- value: "D",
74837
+ value: sourceComp.manufacturer_part_number || "",
74423
74838
  description: "Diode"
74424
74839
  };
74425
74840
  }
@@ -74518,11 +74933,11 @@ var AddSchematicTracesStage = class extends ConverterStage {
74518
74933
  if (!this.ctx.c2kMatSch) {
74519
74934
  throw new Error("Schematic transformation matrix not initialized in context");
74520
74935
  }
74521
- const from = applyToPoint8(this.ctx.c2kMatSch, {
74936
+ const from = applyToPoint10(this.ctx.c2kMatSch, {
74522
74937
  x: edge.from.x,
74523
74938
  y: edge.from.y
74524
74939
  });
74525
- const to = applyToPoint8(this.ctx.c2kMatSch, {
74940
+ const to = applyToPoint10(this.ctx.c2kMatSch, {
74526
74941
  x: edge.to.x,
74527
74942
  y: edge.to.y
74528
74943
  });
@@ -74532,7 +74947,7 @@ var AddSchematicTracesStage = class extends ConverterStage {
74532
74947
  const y2 = to.y;
74533
74948
  const pts = new Pts3([new Xy3(x1, y1), new Xy3(x2, y2)]);
74534
74949
  wire.points = pts;
74535
- const stroke = new Stroke5;
74950
+ const stroke = new Stroke4;
74536
74951
  stroke.width = DEFAULT_LINE_WIDTH_MM;
74537
74952
  stroke.type = "default";
74538
74953
  wire.stroke = stroke;
@@ -74543,7 +74958,7 @@ var AddSchematicTracesStage = class extends ConverterStage {
74543
74958
  if (!this.ctx.c2kMatSch) {
74544
74959
  throw new Error("Schematic transformation matrix not initialized in context");
74545
74960
  }
74546
- const { x, y } = applyToPoint8(this.ctx.c2kMatSch, {
74961
+ const { x, y } = applyToPoint10(this.ctx.c2kMatSch, {
74547
74962
  x: junction.x,
74548
74963
  y: junction.y
74549
74964
  });
@@ -74586,7 +75001,12 @@ var InitializeSchematicStage = class extends ConverterStage {
74586
75001
  }
74587
75002
  kicadSch.version = 20250114;
74588
75003
  const paper = new Paper;
74589
- paper.size = schematicPaperSize?.name ?? "A4";
75004
+ if (schematicPaperSize?.customSize) {
75005
+ paper.customSize = schematicPaperSize.customSize;
75006
+ } else {
75007
+ paper.size = schematicPaperSize?.name ?? "A4";
75008
+ }
75009
+ paper.isPortrait = schematicPaperSize?.isPortrait ?? false;
74590
75010
  kicadSch.paper = paper;
74591
75011
  kicadSch.uuid = new Uuid4(this.ctx.schematicFileUuid ?? crypto.randomUUID());
74592
75012
  this.finished = true;
@@ -74596,7 +75016,34 @@ var InitializeSchematicStage = class extends ConverterStage {
74596
75016
  }
74597
75017
  };
74598
75018
  var DEFAULT_SCHEMATIC_SCALE_FACTOR = 15;
74599
- var DEFAULT_PAPER_PADDING_MM = 20;
75019
+ var COMPACT_LARGE_SHEET_MARGIN_MM = 15;
75020
+ var TITLE_BLOCK_CONTENT_OFFSET_MM = 5;
75021
+ var getSingleSheetSchematicLayout = (db) => {
75022
+ let measurement = getSchematicBoundsAndCenter(db);
75023
+ let contentWidthMm = (measurement.bounds.maxX - measurement.bounds.minX) * DEFAULT_SCHEMATIC_SCALE_FACTOR;
75024
+ let contentHeightMm = (measurement.bounds.maxY - measurement.bounds.minY) * DEFAULT_SCHEMATIC_SCALE_FACTOR;
75025
+ let paperSize = selectSchematicPaperSize(contentWidthMm, contentHeightMm);
75026
+ if (!measurement.hasComponentLevelSourceGeometry || paperSize.name === "A4" || paperSize.name === "A3") {
75027
+ return { ...measurement, paperSize };
75028
+ }
75029
+ measurement = getSchematicBoundsAndCenter(db, {
75030
+ useComponentLevelSourceGeometry: true
75031
+ });
75032
+ contentWidthMm = (measurement.bounds.maxX - measurement.bounds.minX) * DEFAULT_SCHEMATIC_SCALE_FACTOR;
75033
+ contentHeightMm = (measurement.bounds.maxY - measurement.bounds.minY) * DEFAULT_SCHEMATIC_SCALE_FACTOR;
75034
+ paperSize = selectSchematicPaperSize(contentWidthMm, contentHeightMm, COMPACT_LARGE_SHEET_MARGIN_MM);
75035
+ return { ...measurement, paperSize };
75036
+ };
75037
+ var getSchematicSheetOptions = ({
75038
+ options,
75039
+ schematicSheetId
75040
+ }) => options.schematicSheets?.find((sheetOptions) => (sheetOptions.schematicSheetId ?? null) === schematicSheetId);
75041
+ var createSchematicTransform = ({
75042
+ center,
75043
+ circuitOrigin,
75044
+ contentCenter,
75045
+ scaleFactor
75046
+ }) => circuitOrigin ? compose2(translate2(circuitOrigin.x, circuitOrigin.y), scale(scaleFactor, -scaleFactor)) : compose2(translate2(contentCenter.x, contentCenter.y), scale(scaleFactor, -scaleFactor), translate2(-center.x, -center.y));
74600
75047
  var CircuitJsonToKicadSchConverter = class {
74601
75048
  ctx;
74602
75049
  pipeline;
@@ -74606,30 +75053,43 @@ var CircuitJsonToKicadSchConverter = class {
74606
75053
  schematicSheetPlan;
74607
75054
  files = [];
74608
75055
  built = false;
75056
+ options;
74609
75057
  get currentStage() {
74610
75058
  return this.pipeline[this.currentStageIndex];
74611
75059
  }
74612
- constructor(circuitJson) {
75060
+ constructor(circuitJson, options = {}) {
74613
75061
  this.circuitJson = circuitJson;
75062
+ this.options = options;
74614
75063
  this.schematicSheetPlan = buildSchematicSheetPlan(circuitJson);
74615
75064
  const kicadSchematicScaleFactor = DEFAULT_SCHEMATIC_SCALE_FACTOR;
74616
75065
  const db = cju(circuitJson);
74617
- const { center, bounds } = getSchematicBoundsAndCenter(db);
74618
- const schematicWidthMm = (bounds.maxX - bounds.minX) * kicadSchematicScaleFactor;
74619
- const schematicHeightMm = (bounds.maxY - bounds.minY) * kicadSchematicScaleFactor;
74620
- const paperSize = selectSchematicPaperSize(schematicWidthMm, schematicHeightMm);
74621
- const KICAD_CENTER_X = paperSize.width / 2;
74622
- const KICAD_CENTER_Y = paperSize.height / 2;
75066
+ const { center, paperSize: fittedPaperSize } = getSingleSheetSchematicLayout(db);
75067
+ const paperSize = options.paperSize ?? fittedPaperSize;
75068
+ const sheetOptions = getSchematicSheetOptions({
75069
+ options,
75070
+ schematicSheetId: null
75071
+ });
75072
+ const titleBlockContentOffsetMm = options.titleBlock ? TITLE_BLOCK_CONTENT_OFFSET_MM : 0;
75073
+ const contentCenter = {
75074
+ x: paperSize.width / 2,
75075
+ y: paperSize.height / 2 - titleBlockContentOffsetMm
75076
+ };
74623
75077
  this.ctx = {
74624
75078
  db,
74625
75079
  circuitJson,
74626
75080
  kicadSch: new KicadSch({
74627
75081
  generator: "circuit-json-to-kicad",
74628
- generatorVersion: "0.0.1"
75082
+ generatorVersion: "0.0.1",
75083
+ titleBlock: createKicadSchematicTitleBlock(options.titleBlock)
74629
75084
  }),
74630
75085
  kicadSchematicScaleFactor,
74631
75086
  schematicPaperSize: paperSize,
74632
- c2kMatSch: compose2(translate2(KICAD_CENTER_X, KICAD_CENTER_Y), scale(kicadSchematicScaleFactor, -kicadSchematicScaleFactor), translate2(-center.x, -center.y))
75087
+ c2kMatSch: createSchematicTransform({
75088
+ center,
75089
+ circuitOrigin: sheetOptions?.circuitOrigin,
75090
+ contentCenter,
75091
+ scaleFactor: kicadSchematicScaleFactor
75092
+ })
74633
75093
  };
74634
75094
  this.pipeline = [
74635
75095
  new InitializeSchematicStage(circuitJson, this.ctx),
@@ -74695,9 +75155,10 @@ var CircuitJsonToKicadSchConverter = class {
74695
75155
  return;
74696
75156
  this.built = true;
74697
75157
  const { rootUuid, root, children } = this.schematicSheetPlan;
74698
- const { nodes: childSheetNodes, extentMm } = buildChildSheetNodes(children, rootUuid);
75158
+ const { nodes: childSheetNodes, extentMm } = buildChildSheetNodes(children, rootUuid, this.options.schematicSheets);
74699
75159
  const rootSch = this.buildSheetFile({
74700
75160
  circuitJson: partitionCircuitJsonBySheet(this.circuitJson, null),
75161
+ schematicSheetId: null,
74701
75162
  fileUuid: rootUuid,
74702
75163
  symbolInstancePathPrefix: `/${rootUuid}`,
74703
75164
  emitSheetInstances: true,
@@ -74712,6 +75173,7 @@ var CircuitJsonToKicadSchConverter = class {
74712
75173
  for (const child of children) {
74713
75174
  const childSch = this.buildSheetFile({
74714
75175
  circuitJson: partitionCircuitJsonBySheet(this.circuitJson, child.schematicSheetId),
75176
+ schematicSheetId: child.schematicSheetId,
74715
75177
  fileUuid: child.fileUuid,
74716
75178
  symbolInstancePathPrefix: `/${rootUuid}/${child.sheetNodeUuid}`,
74717
75179
  emitSheetInstances: false
@@ -74726,6 +75188,7 @@ var CircuitJsonToKicadSchConverter = class {
74726
75188
  buildSheetFile(options) {
74727
75189
  const {
74728
75190
  circuitJson,
75191
+ schematicSheetId,
74729
75192
  fileUuid,
74730
75193
  symbolInstancePathPrefix,
74731
75194
  emitSheetInstances,
@@ -74735,17 +75198,38 @@ var CircuitJsonToKicadSchConverter = class {
74735
75198
  const kicadSchematicScaleFactor = DEFAULT_SCHEMATIC_SCALE_FACTOR;
74736
75199
  const db = cju(circuitJson);
74737
75200
  const { center, bounds } = getSchematicBoundsAndCenter(db);
74738
- const paperSize = selectSchematicPaperSize(Math.max((bounds.maxX - bounds.minX) * kicadSchematicScaleFactor + 2 * DEFAULT_PAPER_PADDING_MM, extraPaperExtentMm?.width ?? 0), Math.max((bounds.maxY - bounds.minY) * kicadSchematicScaleFactor + 2 * DEFAULT_PAPER_PADDING_MM, extraPaperExtentMm?.height ?? 0), 0);
75201
+ const schematicWidthMm = (bounds.maxX - bounds.minX) * kicadSchematicScaleFactor;
75202
+ const schematicHeightMm = (bounds.maxY - bounds.minY) * kicadSchematicScaleFactor;
75203
+ const { paperSize: fittedPaperSize, contentCenter: fittedContentCenter } = getSchematicPageLayout({
75204
+ contentWidthMm: schematicWidthMm,
75205
+ contentHeightMm: schematicHeightMm,
75206
+ extraPaperExtentMm
75207
+ });
75208
+ const paperSize = this.options.paperSize ?? fittedPaperSize;
75209
+ const sheetOptions = getSchematicSheetOptions({
75210
+ options: this.options,
75211
+ schematicSheetId
75212
+ });
75213
+ const contentCenter = this.options.paperSize ? { x: paperSize.width / 2, y: paperSize.height / 2 } : fittedContentCenter;
75214
+ if (this.options.titleBlock) {
75215
+ contentCenter.y -= TITLE_BLOCK_CONTENT_OFFSET_MM;
75216
+ }
74739
75217
  const ctx = {
74740
75218
  db,
74741
75219
  circuitJson,
74742
75220
  kicadSch: new KicadSch({
74743
75221
  generator: "circuit-json-to-kicad",
74744
- generatorVersion: "0.0.1"
75222
+ generatorVersion: "0.0.1",
75223
+ titleBlock: createKicadSchematicTitleBlock(this.options.titleBlock)
74745
75224
  }),
74746
75225
  kicadSchematicScaleFactor,
74747
75226
  schematicPaperSize: paperSize,
74748
- c2kMatSch: compose2(translate2(paperSize.width / 2, paperSize.height / 2), scale(kicadSchematicScaleFactor, -kicadSchematicScaleFactor), translate2(-center.x, -center.y)),
75227
+ c2kMatSch: createSchematicTransform({
75228
+ center,
75229
+ circuitOrigin: sheetOptions?.circuitOrigin,
75230
+ contentCenter,
75231
+ scaleFactor: kicadSchematicScaleFactor
75232
+ }),
74749
75233
  schematicFileUuid: fileUuid,
74750
75234
  symbolInstancePathPrefix
74751
75235
  };
@@ -74867,7 +75351,7 @@ var getCopperPourNetInfo = (pour, ctx) => {
74867
75351
  };
74868
75352
  var convertPointsToKicadXy = (points, c2kMatPcb) => {
74869
75353
  return (points ?? []).map((point) => {
74870
- const transformedPoint = applyToPoint9(c2kMatPcb, point);
75354
+ const transformedPoint = applyToPoint11(c2kMatPcb, point);
74871
75355
  return new Xy4(transformedPoint.x, transformedPoint.y);
74872
75356
  });
74873
75357
  };
@@ -74916,7 +75400,7 @@ var getRectRingPoints = (pour, c2kMatPcb) => {
74916
75400
  { x: halfWidth, y: -halfHeight },
74917
75401
  { x: halfWidth, y: halfHeight },
74918
75402
  { x: -halfWidth, y: halfHeight }
74919
- ].map((corner) => applyToPoint9(cornerTransform, corner));
75403
+ ].map((corner) => applyToPoint11(cornerTransform, corner));
74920
75404
  return convertPointsToKicadXy(corners, c2kMatPcb);
74921
75405
  };
74922
75406
  var getPolygonRingPoints = (pour, c2kMatPcb) => removeRepeatedClosingPoint(removeConsecutiveDuplicatePoints(rotateRingToStartAtTopRight(convertPointsToKicadXy(pour.points, c2kMatPcb))));
@@ -75088,7 +75572,7 @@ var AddKeepoutsStage = class extends ConverterStage {
75088
75572
  rawPoints = keepout.outline;
75089
75573
  }
75090
75574
  const kicadPoints = rawPoints.map((p) => {
75091
- const t = applyToPoint10(c2kMatPcb, p);
75575
+ const t = applyToPoint12(c2kMatPcb, p);
75092
75576
  return new Xy5(t.x, t.y);
75093
75577
  });
75094
75578
  const zone = new Zone2({
@@ -75646,21 +76130,24 @@ function getkicadComponentProperty(sourceComp) {
75646
76130
  supplierPartNumber
75647
76131
  };
75648
76132
  }
75649
- function convertSilkscreenCircles(silkscreenCircles, componentCenter) {
76133
+ function convertSilkscreenCircles(silkscreenCircles, { componentCenter, componentRotation = 0 }) {
75650
76134
  const fpCircles = [];
76135
+ const rotationMatrix = componentRotation !== 0 ? rotate2(componentRotation * Math.PI / 180) : identity();
75651
76136
  for (const circle of silkscreenCircles) {
75652
- const relX = circle.center.x - componentCenter.x;
75653
- const relY = -(circle.center.y - componentCenter.y);
76137
+ const relativeCenter = applyToPoint13(rotationMatrix, {
76138
+ x: circle.center.x - componentCenter.x,
76139
+ y: -(circle.center.y - componentCenter.y)
76140
+ });
75654
76141
  const layerMap = {
75655
76142
  top: "F.SilkS",
75656
76143
  bottom: "B.SilkS"
75657
76144
  };
75658
76145
  const kicadLayer = layerMap[circle.layer] || circle.layer || "F.SilkS";
75659
76146
  const fpCircle = new FpCircle({
75660
- center: { x: relX, y: relY },
75661
- end: { x: relX + circle.radius, y: relY },
76147
+ center: relativeCenter,
76148
+ end: { x: relativeCenter.x + circle.radius, y: relativeCenter.y },
75662
76149
  layer: kicadLayer,
75663
- stroke: new Stroke6,
76150
+ stroke: new Stroke5,
75664
76151
  fill: false
75665
76152
  });
75666
76153
  if (fpCircle.stroke) {
@@ -75685,7 +76172,7 @@ function convertCourtyardCircles(courtyardCircles, componentCenter) {
75685
76172
  center: { x: relX, y: relY },
75686
76173
  end: { x: relX + circle.radius, y: relY },
75687
76174
  layer: kicadLayer,
75688
- stroke: new Stroke7,
76175
+ stroke: new Stroke6,
75689
76176
  fill: false
75690
76177
  });
75691
76178
  if (fpCircle.stroke) {
@@ -75712,7 +76199,7 @@ function convertFabricationNoteRects(fabRects, componentCenter) {
75712
76199
  start: { x: relX - halfW, y: relY - halfH },
75713
76200
  end: { x: relX + halfW, y: relY + halfH },
75714
76201
  layer: kicadLayer,
75715
- stroke: new Stroke8,
76202
+ stroke: new Stroke7,
75716
76203
  fill: false
75717
76204
  });
75718
76205
  if (fpRect.stroke) {
@@ -75735,7 +76222,7 @@ function convertNoteRects(noteRects, componentCenter) {
75735
76222
  start: { x: relX - halfW, y: relY - halfH },
75736
76223
  end: { x: relX + halfW, y: relY + halfH },
75737
76224
  layer: kicadLayer,
75738
- stroke: new Stroke9,
76225
+ stroke: new Stroke8,
75739
76226
  fill: false
75740
76227
  });
75741
76228
  if (fpRect.stroke) {
@@ -75762,7 +76249,7 @@ function convertCourtyardRects(courtyardRects, componentCenter) {
75762
76249
  start: { x: relX - halfW, y: relY - halfH },
75763
76250
  end: { x: relX + halfW, y: relY + halfH },
75764
76251
  layer: kicadLayer,
75765
- stroke: new Stroke10,
76252
+ stroke: new Stroke9,
75766
76253
  fill: false
75767
76254
  });
75768
76255
  if (fpRect.stroke) {
@@ -75776,7 +76263,7 @@ function convertCourtyardRects(courtyardRects, componentCenter) {
75776
76263
  function convertCourtyardOutlines(params2) {
75777
76264
  const { courtyardOutlines, componentCenter, componentRotation = 0 } = params2;
75778
76265
  const fpPolys = [];
75779
- const cj2kicadMatrix = compose4(componentRotation !== 0 ? rotate2(componentRotation * Math.PI / 180) : { a: 1, b: 0, c: 0, d: 1, e: 0, f: 0 }, scale2(1, -1), translate4(-componentCenter.x, -componentCenter.y));
76266
+ const cj2kicadMatrix = compose4(componentRotation !== 0 ? rotate3(componentRotation * Math.PI / 180) : { a: 1, b: 0, c: 0, d: 1, e: 0, f: 0 }, scale2(1, -1), translate4(-componentCenter.x, -componentCenter.y));
75780
76267
  for (const outline of courtyardOutlines) {
75781
76268
  if (!outline.outline || outline.outline.length < 2)
75782
76269
  continue;
@@ -75786,7 +76273,7 @@ function convertCourtyardOutlines(params2) {
75786
76273
  };
75787
76274
  const kicadLayer = layerMap[outline.layer] || "F.CrtYd";
75788
76275
  const xyPoints = outline.outline.map((point) => {
75789
- const transformedPoint = applyToPoint11(cj2kicadMatrix, point);
76276
+ const transformedPoint = applyToPoint14(cj2kicadMatrix, point);
75790
76277
  return new Xy6(transformedPoint.x, transformedPoint.y);
75791
76278
  });
75792
76279
  const fpPoly = new FpPoly;
@@ -75794,7 +76281,7 @@ function convertCourtyardOutlines(params2) {
75794
76281
  fpPoly.layer = kicadLayer;
75795
76282
  fpPoly.fill = false;
75796
76283
  fpPoly.uuid = generateDeterministicUuid(outline.pcb_courtyard_outline_id);
75797
- const stroke = new Stroke11;
76284
+ const stroke = new Stroke10;
75798
76285
  stroke.width = 0.05;
75799
76286
  stroke.type = "default";
75800
76287
  fpPoly.stroke = stroke;
@@ -75859,8 +76346,8 @@ function createFpTextFromCircuitJson({
75859
76346
  }
75860
76347
  const relativeX = textElement.anchor_position.x - componentCenter.x;
75861
76348
  const relativeY = -(textElement.anchor_position.y - componentCenter.y);
75862
- const rotationMatrix = componentRotation !== 0 ? rotate3(componentRotation * Math.PI / 180) : identity();
75863
- const rotatedPos = applyToPoint12(rotationMatrix, {
76349
+ const rotationMatrix = componentRotation !== 0 ? rotate4(componentRotation * Math.PI / 180) : identity2();
76350
+ const rotatedPos = applyToPoint15(rotationMatrix, {
75864
76351
  x: relativeX,
75865
76352
  y: relativeY
75866
76353
  });
@@ -75926,7 +76413,7 @@ function convertSilkscreenTexts(params2) {
75926
76413
  }
75927
76414
  function convertSilkscreenPaths(silkscreenPaths, { componentCenter, componentRotation = 0 }) {
75928
76415
  const fpLines = [];
75929
- const rotationMatrix = componentRotation !== 0 ? rotate4(componentRotation * Math.PI / 180) : identity2();
76416
+ const rotationMatrix = componentRotation !== 0 ? rotate5(componentRotation * Math.PI / 180) : identity3();
75930
76417
  for (const path of silkscreenPaths) {
75931
76418
  if (!path.route || path.route.length < 2)
75932
76419
  continue;
@@ -75940,11 +76427,11 @@ function convertSilkscreenPaths(silkscreenPaths, { componentCenter, componentRot
75940
76427
  const endPoint = path.route[i + 1];
75941
76428
  if (!startPoint || !endPoint)
75942
76429
  continue;
75943
- const startRelative = applyToPoint13(rotationMatrix, {
76430
+ const startRelative = applyToPoint16(rotationMatrix, {
75944
76431
  x: startPoint.x - componentCenter.x,
75945
76432
  y: -(startPoint.y - componentCenter.y)
75946
76433
  });
75947
- const endRelative = applyToPoint13(rotationMatrix, {
76434
+ const endRelative = applyToPoint16(rotationMatrix, {
75948
76435
  x: endPoint.x - componentCenter.x,
75949
76436
  y: -(endPoint.y - componentCenter.y)
75950
76437
  });
@@ -75952,7 +76439,7 @@ function convertSilkscreenPaths(silkscreenPaths, { componentCenter, componentRot
75952
76439
  start: { x: startRelative.x, y: startRelative.y },
75953
76440
  end: { x: endRelative.x, y: endRelative.y },
75954
76441
  layer: kicadLayer,
75955
- stroke: new Stroke12
76442
+ stroke: new Stroke11
75956
76443
  });
75957
76444
  if (fpLine.stroke) {
75958
76445
  fpLine.stroke.width = path.stroke_width || 0.15;
@@ -75969,8 +76456,8 @@ function convertNoteTexts(params2) {
75969
76456
  for (const textElement of noteTexts) {
75970
76457
  const relX = textElement.anchor_position.x - componentCenter.x;
75971
76458
  const relY = -(textElement.anchor_position.y - componentCenter.y);
75972
- const rotationMatrix = componentRotation !== 0 ? rotate5(componentRotation * Math.PI / 180) : identity3();
75973
- const rotatedPos = applyToPoint14(rotationMatrix, { x: relX, y: relY });
76459
+ const rotationMatrix = componentRotation !== 0 ? rotate6(componentRotation * Math.PI / 180) : identity4();
76460
+ const rotatedPos = applyToPoint17(rotationMatrix, { x: relX, y: relY });
75974
76461
  const fontSize = textElement.font_size || 1;
75975
76462
  const font = new TextEffectsFont11;
75976
76463
  font.size = { width: fontSize, height: fontSize };
@@ -75986,29 +76473,103 @@ function convertNoteTexts(params2) {
75986
76473
  }
75987
76474
  return fpTexts;
75988
76475
  }
76476
+ var degreesToRadians = (degrees) => degrees * Math.PI / 180;
76477
+ function rotatePointAroundAxis(point, axis, degrees) {
76478
+ const c = Math.cos(degreesToRadians(degrees));
76479
+ const s = Math.sin(degreesToRadians(degrees));
76480
+ const { x, y, z } = point;
76481
+ if (axis === "x")
76482
+ return { x, y: c * y - s * z, z: s * y + c * z };
76483
+ if (axis === "y")
76484
+ return { x: c * x + s * z, y, z: -s * x + c * z };
76485
+ return { x: c * x - s * y, y: s * x + c * y, z };
76486
+ }
76487
+ function applyCadRotationToPoint(point, rotation) {
76488
+ const rotatedAroundZ = rotatePointAroundAxis(point, "z", rotation.z);
76489
+ const rotatedAroundX = rotatePointAroundAxis(rotatedAroundZ, "x", -rotation.x);
76490
+ return rotatePointAroundAxis(rotatedAroundX, "y", -rotation.y);
76491
+ }
76492
+ function getKicadFootprintLocalModelTransform(cadComponent, {
76493
+ componentCenter,
76494
+ footprintRotation,
76495
+ boardLayerZOffset,
76496
+ layer
76497
+ }) {
76498
+ const position = cadComponent.position;
76499
+ const rotation = cadComponent.rotation ?? {
76500
+ x: layer === "bottom" ? 180 : 0,
76501
+ y: 0,
76502
+ z: 0
76503
+ };
76504
+ const origin = cadComponent.model_origin_position ?? { x: 0, y: 0, z: 0 };
76505
+ const toLocal = (point) => {
76506
+ const p = rotatePointAroundAxis(point, "z", -footprintRotation);
76507
+ return layer === "bottom" ? { x: p.x, y: -p.y, z: -p.z } : p;
76508
+ };
76509
+ const modelToLocal = (point) => toLocal(applyCadRotationToPoint(point, rotation));
76510
+ const x = modelToLocal({ x: 1, y: 0, z: 0 });
76511
+ const y = modelToLocal({ x: 0, y: 1, z: 0 });
76512
+ const z = modelToLocal({ x: 0, y: 0, z: 1 });
76513
+ const singular = Math.hypot(x.x, x.y) < 0.0000000001;
76514
+ const degrees = (angle) => {
76515
+ return Math.round(angle * 180 / Math.PI * 10000000000) / 10000000000 || 0;
76516
+ };
76517
+ const localRotation = {
76518
+ x: singular ? 0 : degrees(-Math.atan2(y.z, z.z)),
76519
+ y: degrees(Math.atan2(x.z, Math.hypot(x.x, x.y))),
76520
+ z: degrees(singular ? Math.atan2(y.x, y.y) : -Math.atan2(x.y, x.x))
76521
+ };
76522
+ const localPosition = toLocal({
76523
+ x: position.x - componentCenter.x,
76524
+ y: position.y - componentCenter.y,
76525
+ z: position.z - boardLayerZOffset
76526
+ });
76527
+ const localOrigin = modelToLocal(origin);
76528
+ return {
76529
+ offset: {
76530
+ x: localPosition.x - localOrigin.x,
76531
+ y: localPosition.y - localOrigin.y,
76532
+ z: localPosition.z - localOrigin.z
76533
+ },
76534
+ rotation: localRotation
76535
+ };
76536
+ }
76537
+ var getEasyedaModelCdnStepUrl = (objUrl) => {
76538
+ if (!objUrl)
76539
+ return;
76540
+ try {
76541
+ const url = new URL(objUrl);
76542
+ if (url.hostname !== "modelcdn.tscircuit.com")
76543
+ return;
76544
+ const assetMatch = url.pathname.match(/^\/easyeda_models\/assets\/([^/]+)\.obj$/);
76545
+ const partNumber = assetMatch?.[1] ?? url.searchParams.get("pn");
76546
+ const isLegacyDownload = url.pathname === "/easyeda_models/download";
76547
+ if (!partNumber || !assetMatch && !isLegacyDownload)
76548
+ return;
76549
+ const stepUrl = new URL(`/easyeda_models/assets/${encodeURIComponent(partNumber)}.step`, url.origin);
76550
+ const uuid = url.searchParams.get("uuid");
76551
+ if (uuid)
76552
+ stepUrl.searchParams.set("uuid", uuid);
76553
+ return stepUrl.toString();
76554
+ } catch {
76555
+ return;
76556
+ }
76557
+ };
75989
76558
  function create3DModelsFromCadComponent(cadComponent, componentCenter, options) {
75990
76559
  const models = [];
75991
- const modelUrl = cadComponent.model_step_url || cadComponent.model_wrl_url;
76560
+ const modelUrl = cadComponent.model_step_url || cadComponent.model_wrl_url || getEasyedaModelCdnStepUrl(cadComponent.model_obj_url);
75992
76561
  if (!modelUrl)
75993
76562
  return models;
75994
76563
  const model = new FootprintModel3(modelUrl);
75995
- if (cadComponent.position) {
75996
- const boardLayerZOffset = options?.boardLayerZOffset ?? 0;
75997
- const modelOriginPosition = cadComponent.model_origin_position;
75998
- model.offset = {
75999
- x: (cadComponent.position.x || 0) - componentCenter.x - (modelOriginPosition?.x || 0),
76000
- y: (cadComponent.position.y || 0) - componentCenter.y - (modelOriginPosition?.y || 0),
76001
- z: (cadComponent.position.z || 0) - boardLayerZOffset - (modelOriginPosition?.z || 0)
76002
- };
76003
- }
76004
- if (cadComponent.rotation) {
76005
- const footprintRotation = options?.footprintRotation ?? 0;
76006
- model.rotate = {
76007
- x: cadComponent.rotation.x || 0,
76008
- y: cadComponent.rotation.y || 0,
76009
- z: (cadComponent.rotation.z || 0) - footprintRotation
76010
- };
76011
- }
76564
+ const boardLayerZOffset = options.boardLayerZOffset ?? 0;
76565
+ const transform = getKicadFootprintLocalModelTransform(cadComponent, {
76566
+ componentCenter,
76567
+ footprintRotation: options.footprintRotation,
76568
+ boardLayerZOffset,
76569
+ layer: options.layer
76570
+ });
76571
+ model.offset = transform.offset;
76572
+ model.rotate = transform.rotation;
76012
76573
  if (cadComponent.model_unit_to_mm_scale_factor) {
76013
76574
  const scale5 = cadComponent.model_unit_to_mm_scale_factor;
76014
76575
  model.scale = { x: scale5, y: scale5, z: scale5 };
@@ -76036,8 +76597,8 @@ function createSmdPadFromCircuitJson({
76036
76597
  } else {
76037
76598
  throw new Error("Pad must have either x/y coordinates or points array");
76038
76599
  }
76039
- const cj2kicadMatrix = compose5(componentRotation !== 0 ? rotate6(componentRotation * Math.PI / 180) : { a: 1, b: 0, c: 0, d: 1, e: 0, f: 0 }, scale3(1, -1), translate5(-componentCenter.x, -componentCenter.y));
76040
- const rotatedPos = applyToPoint15(cj2kicadMatrix, {
76600
+ const cj2kicadMatrix = compose5(componentRotation !== 0 ? rotate7(componentRotation * Math.PI / 180) : { a: 1, b: 0, c: 0, d: 1, e: 0, f: 0 }, scale3(1, -1), translate5(-componentCenter.x, -componentCenter.y));
76601
+ const rotatedPos = applyToPoint18(cj2kicadMatrix, {
76041
76602
  x: padX,
76042
76603
  y: padY
76043
76604
  });
@@ -76062,7 +76623,7 @@ function createSmdPadFromCircuitJson({
76062
76623
  const points = pcbPad.points;
76063
76624
  const pointTransformMatrix = compose5(scale3(1, -1), translate5(-padX, -padY));
76064
76625
  const relativePoints = points.map((p) => {
76065
- const transformed = applyToPoint15(pointTransformMatrix, { x: p.x, y: p.y });
76626
+ const transformed = applyToPoint18(pointTransformMatrix, { x: p.x, y: p.y });
76066
76627
  return new Xy7(transformed.x, transformed.y);
76067
76628
  });
76068
76629
  const grPoly = new PadPrimitiveGrPoly;
@@ -76174,8 +76735,8 @@ function createThruHolePadFromCircuitJson({
76174
76735
  }
76175
76736
  const relativeX = platedHole.x - componentCenter.x;
76176
76737
  const relativeY = -(platedHole.y - componentCenter.y);
76177
- const rotationMatrix = componentRotation !== 0 ? rotate7(componentRotation * Math.PI / 180) : identity4();
76178
- const rotatedPos = applyToPoint16(rotationMatrix, {
76738
+ const rotationMatrix = componentRotation !== 0 ? rotate8(componentRotation * Math.PI / 180) : identity5();
76739
+ const rotatedPos = applyToPoint19(rotationMatrix, {
76179
76740
  x: relativeX,
76180
76741
  y: relativeY
76181
76742
  });
@@ -76191,7 +76752,7 @@ function createThruHolePadFromCircuitJson({
76191
76752
  y: platedHole.hole_offset_y ?? 0
76192
76753
  };
76193
76754
  if (rawOffset.x !== 0 || rawOffset.y !== 0) {
76194
- const rotatedOffset = applyToPoint16(rotationMatrix, {
76755
+ const rotatedOffset = applyToPoint19(rotationMatrix, {
76195
76756
  x: -rawOffset.x,
76196
76757
  y: rawOffset.y
76197
76758
  });
@@ -76306,8 +76867,8 @@ function createNpthPadFromCircuitJson({
76306
76867
  }
76307
76868
  const relativeX = pcbHole.x - componentCenter.x;
76308
76869
  const relativeY = -(pcbHole.y - componentCenter.y);
76309
- const rotationMatrix = componentRotation !== 0 ? rotate8(componentRotation * Math.PI / 180) : identity5();
76310
- const rotatedPos = applyToPoint17(rotationMatrix, {
76870
+ const rotationMatrix = componentRotation !== 0 ? rotate9(componentRotation * Math.PI / 180) : identity6();
76871
+ const rotatedPos = applyToPoint20(rotationMatrix, {
76311
76872
  x: relativeX,
76312
76873
  y: relativeY
76313
76874
  });
@@ -76376,6 +76937,42 @@ function convertNpthHoles(params2) {
76376
76937
  }
76377
76938
  return pads;
76378
76939
  }
76940
+ function convertFabricationNotePaths(fabricationNotePaths, {
76941
+ componentCenter,
76942
+ componentRotation = 0
76943
+ }) {
76944
+ const fpLines = [];
76945
+ const rotationMatrix = componentRotation !== 0 ? rotate10(componentRotation * Math.PI / 180) : identity7();
76946
+ for (const fabricationNotePath of fabricationNotePaths) {
76947
+ if (fabricationNotePath.route.length < 2)
76948
+ continue;
76949
+ const kicadLayer = fabricationNotePath.layer === "bottom" ? "B.Fab" : "F.Fab";
76950
+ for (let index = 0;index < fabricationNotePath.route.length - 1; index++) {
76951
+ const startPoint = fabricationNotePath.route[index];
76952
+ const endPoint = fabricationNotePath.route[index + 1];
76953
+ if (!startPoint || !endPoint)
76954
+ continue;
76955
+ const startRelative = applyToPoint21(rotationMatrix, {
76956
+ x: startPoint.x - componentCenter.x,
76957
+ y: -(startPoint.y - componentCenter.y)
76958
+ });
76959
+ const endRelative = applyToPoint21(rotationMatrix, {
76960
+ x: endPoint.x - componentCenter.x,
76961
+ y: -(endPoint.y - componentCenter.y)
76962
+ });
76963
+ const stroke = new Stroke12;
76964
+ stroke.width = fabricationNotePath.stroke_width || 0.1;
76965
+ stroke.type = "default";
76966
+ fpLines.push(new FpLine2({
76967
+ start: startRelative,
76968
+ end: endRelative,
76969
+ layer: kicadLayer,
76970
+ stroke
76971
+ }));
76972
+ }
76973
+ }
76974
+ return fpLines;
76975
+ }
76379
76976
  var AddFootprintsStage = class extends ConverterStage {
76380
76977
  componentsProcessed = 0;
76381
76978
  pcbComponents = [];
@@ -76422,7 +77019,7 @@ var AddFootprintsStage = class extends ConverterStage {
76422
77019
  const sourceComponent = component.source_component_id ? this.ctx.db.source_component.get(component.source_component_id) : null;
76423
77020
  const cadComponent = this.getCadComponentForPcbComponent(component.pcb_component_id);
76424
77021
  const footprintName = sourceComponent ? getKicadCompatibleComponentName(sourceComponent, cadComponent) : "Unknown";
76425
- const transformedPos = applyToPoint18(c2kMatPcb, {
77022
+ const transformedPos = applyToPoint22(c2kMatPcb, {
76426
77023
  x: component.center.x,
76427
77024
  y: component.center.y
76428
77025
  });
@@ -76454,6 +77051,11 @@ var AddFootprintsStage = class extends ConverterStage {
76454
77051
  componentCenter: component.center,
76455
77052
  componentRotation: component.rotation || 0
76456
77053
  }));
77054
+ const fabricationNotePaths = this.ctx.db.pcb_fabrication_note_path?.list().filter((path) => path.pcb_component_id === component.pcb_component_id) || [];
77055
+ fpLines.push(...convertFabricationNotePaths(fabricationNotePaths, {
77056
+ componentCenter: component.center,
77057
+ componentRotation: component.rotation || 0
77058
+ }));
76457
77059
  footprint.fpLines = fpLines;
76458
77060
  const fpPads = footprint.fpPads;
76459
77061
  const getNetInfo = (pcbPortId) => this.getNetInfoForPcbPort(pcbPortId);
@@ -76487,7 +77089,10 @@ var AddFootprintsStage = class extends ConverterStage {
76487
77089
  footprint.fpPads = fpPads;
76488
77090
  const pcbSilkscreenCircles = this.ctx.db.pcb_silkscreen_circle?.list().filter((circle) => circle.pcb_component_id === component.pcb_component_id) || [];
76489
77091
  const fpCircles = footprint.fpCircles ?? [];
76490
- fpCircles.push(...convertSilkscreenCircles(pcbSilkscreenCircles, component.center));
77092
+ fpCircles.push(...convertSilkscreenCircles(pcbSilkscreenCircles, {
77093
+ componentCenter: component.center,
77094
+ componentRotation: component.rotation || 0
77095
+ }));
76491
77096
  const pcbCourtyardCircles = this.ctx.db.pcb_courtyard_circle?.list().filter((circle) => circle.pcb_component_id === component.pcb_component_id) || [];
76492
77097
  fpCircles.push(...convertCourtyardCircles(pcbCourtyardCircles, component.center));
76493
77098
  footprint.fpCircles = fpCircles;
@@ -76514,7 +77119,8 @@ var AddFootprintsStage = class extends ConverterStage {
76514
77119
  const boardLayerZOffset = component.layer === "bottom" ? -(boardThickness / 2) : boardThickness / 2;
76515
77120
  const models = create3DModelsFromCadComponent(cadComponent, component.center, {
76516
77121
  boardLayerZOffset,
76517
- footprintRotation: component.rotation || 0
77122
+ footprintRotation: component.rotation || 0,
77123
+ layer: component.layer
76518
77124
  });
76519
77125
  const KICAD_3D_BASE = "${KIPRJMOD}/3dmodels";
76520
77126
  if (models.length > 0) {
@@ -76633,8 +77239,8 @@ var AddTracesStage = class extends ConverterStage {
76633
77239
  if (!startPosition || !endPosition) {
76634
77240
  throw new Error(`Unable to convert pcb_trace route segment ${trace.pcb_trace_id ?? this.tracesProcessed}:${i} to KiCad segment`);
76635
77241
  }
76636
- const transformedStart = applyToPoint19(c2kMatPcb, startPosition);
76637
- const transformedEnd = applyToPoint19(c2kMatPcb, endPosition);
77242
+ const transformedStart = applyToPoint23(c2kMatPcb, startPosition);
77243
+ const transformedEnd = applyToPoint23(c2kMatPcb, endPosition);
76638
77244
  if (transformedStart.x === transformedEnd.x && transformedStart.y === transformedEnd.y) {
76639
77245
  continue;
76640
77246
  }
@@ -76758,7 +77364,7 @@ var AddViasStage = class extends ConverterStage {
76758
77364
  this.finished = true;
76759
77365
  return;
76760
77366
  }
76761
- const transformedPos = applyToPoint20(c2kMatPcb, {
77367
+ const transformedPos = applyToPoint24(c2kMatPcb, {
76762
77368
  x: via.x,
76763
77369
  y: via.y
76764
77370
  });
@@ -76854,7 +77460,7 @@ var AddStandalonePcbElements = class extends ConverterStage {
76854
77460
  const pcbPad = elm;
76855
77461
  const padCenter = this.getPcbSmtPadCenter(pcbPad);
76856
77462
  const footprintSeed = `standalone_smtpad:${pcbPad.pcb_smtpad_id}:${padCenter.x},${padCenter.y}`;
76857
- const kicadPos = applyToPoint21(c2kMatPcb, padCenter);
77463
+ const kicadPos = applyToPoint25(c2kMatPcb, padCenter);
76858
77464
  const footprint = new Footprint4({
76859
77465
  libraryLink: this.getSmtPadLibraryLink(pcbPad),
76860
77466
  layer: "F.Cu",
@@ -76876,7 +77482,7 @@ var AddStandalonePcbElements = class extends ConverterStage {
76876
77482
  } else if (elm.type === "pcb_hole") {
76877
77483
  const hole = elm;
76878
77484
  const footprintSeed = `standalone_hole:${hole.pcb_hole_id}:${hole.x},${hole.y}`;
76879
- const kicadPos = applyToPoint21(c2kMatPcb, { x: hole.x, y: hole.y });
77485
+ const kicadPos = applyToPoint25(c2kMatPcb, { x: hole.x, y: hole.y });
76880
77486
  const libraryLink = this.getHoleLibraryLink(hole);
76881
77487
  const footprint = new Footprint4({
76882
77488
  libraryLink,
@@ -76899,7 +77505,7 @@ var AddStandalonePcbElements = class extends ConverterStage {
76899
77505
  } else if (elm.type === "pcb_plated_hole") {
76900
77506
  const hole = elm;
76901
77507
  const footprintSeed = `standalone_plated_hole:${hole.pcb_plated_hole_id}:${hole.x},${hole.y}`;
76902
- const kicadPos = applyToPoint21(c2kMatPcb, { x: hole.x, y: hole.y });
77508
+ const kicadPos = applyToPoint25(c2kMatPcb, { x: hole.x, y: hole.y });
76903
77509
  const libraryLink = this.getPlatedHoleLibraryLink(hole);
76904
77510
  const footprint = new Footprint4({
76905
77511
  libraryLink,
@@ -76996,7 +77602,7 @@ function createFabricationNoteTextFromCircuitJson({
76996
77602
  if (!textElement.text || !textElement.anchor_position) {
76997
77603
  return null;
76998
77604
  }
76999
- const transformedPos = applyToPoint22(c2kMatPcb, {
77605
+ const transformedPos = applyToPoint26(c2kMatPcb, {
77000
77606
  x: textElement.anchor_position.x,
77001
77607
  y: textElement.anchor_position.y
77002
77608
  });
@@ -77054,7 +77660,7 @@ function createGrTextFromCircuitJson({
77054
77660
  if (!textElement.text || !textElement.anchor_position) {
77055
77661
  return null;
77056
77662
  }
77057
- const transformedPos = applyToPoint23(c2kMatPcb, {
77663
+ const transformedPos = applyToPoint27(c2kMatPcb, {
77058
77664
  x: textElement.anchor_position.x,
77059
77665
  y: textElement.anchor_position.y
77060
77666
  });
@@ -77112,7 +77718,7 @@ var appendGraphicLine = (kicadPcb, grLine) => {
77112
77718
  var rotatePointAroundOrigin = (point, rotationDegrees = 0) => {
77113
77719
  if (!rotationDegrees)
77114
77720
  return point;
77115
- return applyToPoint24(rotate9(rotationDegrees * Math.PI / 180), point);
77721
+ return applyToPoint28(rotate11(rotationDegrees * Math.PI / 180), point);
77116
77722
  };
77117
77723
  var getRectCutoutCorners = (cutout) => {
77118
77724
  const halfWidth = cutout.width / 2;
@@ -77149,11 +77755,11 @@ var AddGraphicsStage = class extends ConverterStage {
77149
77755
  const endPoint = path.route[i + 1];
77150
77756
  if (!startPoint || !endPoint)
77151
77757
  continue;
77152
- const transformedStart = applyToPoint24(c2kMatPcb, {
77758
+ const transformedStart = applyToPoint28(c2kMatPcb, {
77153
77759
  x: startPoint.x,
77154
77760
  y: startPoint.y
77155
77761
  });
77156
- const transformedEnd = applyToPoint24(c2kMatPcb, {
77762
+ const transformedEnd = applyToPoint28(c2kMatPcb, {
77157
77763
  x: endPoint.x,
77158
77764
  y: endPoint.y
77159
77765
  });
@@ -77233,7 +77839,7 @@ var AddGraphicsStage = class extends ConverterStage {
77233
77839
  }
77234
77840
  for (const poly of boardGeom) {
77235
77841
  for (const ring of poly) {
77236
- const transformedRing = ring.map((point) => applyToPoint24(c2kMatPcb, { x: point[0], y: point[1] }));
77842
+ const transformedRing = ring.map((point) => applyToPoint28(c2kMatPcb, { x: point[0], y: point[1] }));
77237
77843
  for (let i = 0;i < transformedRing.length; i++) {
77238
77844
  const start = transformedRing[i];
77239
77845
  const end = transformedRing[(i + 1) % transformedRing.length];
@@ -77262,8 +77868,8 @@ var AddGraphicsStage = class extends ConverterStage {
77262
77868
  const endPoint = cutout.route[i + 1];
77263
77869
  if (!startPoint || !endPoint)
77264
77870
  continue;
77265
- const transformedStart = applyToPoint24(c2kMatPcb, startPoint);
77266
- const transformedEnd = applyToPoint24(c2kMatPcb, endPoint);
77871
+ const transformedStart = applyToPoint28(c2kMatPcb, startPoint);
77872
+ const transformedEnd = applyToPoint28(c2kMatPcb, endPoint);
77267
77873
  appendGraphicLine(kicadPcb, new GrLine({
77268
77874
  start: transformedStart,
77269
77875
  end: transformedEnd,