@tscircuit/core 0.0.892 → 0.0.893

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.
Files changed (3) hide show
  1. package/dist/index.d.ts +12 -4
  2. package/dist/index.js +2151 -2142
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -143,6 +143,7 @@ var orderedRenderPhases = [
143
143
  "PcbComponentAnchorAlignment",
144
144
  "PcbLayout",
145
145
  "PcbBoardAutoSize",
146
+ "PanelLayout",
146
147
  "PcbTraceHintRender",
147
148
  "PcbManualTraceRender",
148
149
  "PcbTraceRender",
@@ -3618,7 +3619,7 @@ var createComponentsFromCircuitJson = ({
3618
3619
  components.push(
3619
3620
  new SilkscreenText({
3620
3621
  anchorAlignment: elm.anchor_alignment || "center",
3621
- text: componentName,
3622
+ text: componentName || elm.text,
3622
3623
  fontSize: elm.font_size + 0.2,
3623
3624
  pcbX: Number.isNaN(elm.anchor_position.x) ? 0 : elm.anchor_position.x,
3624
3625
  pcbY: elm.anchor_position.y,
@@ -14487,327 +14488,1219 @@ var Group6 = class extends NormalComponent3 {
14487
14488
  }
14488
14489
  };
14489
14490
 
14490
- // lib/components/normal-components/Board.ts
14491
- import {
14492
- checkEachPcbPortConnectedToPcbTraces,
14493
- checkEachPcbTraceNonOverlapping,
14494
- checkPcbComponentsOutOfBoard,
14495
- checkPcbTracesOutOfBoard,
14496
- checkDifferentNetViaSpacing,
14497
- checkSameNetViaSpacing,
14498
- checkPcbComponentOverlap,
14499
- checkPinMustBeConnected
14500
- } from "@tscircuit/checks";
14501
- import { getBoundsFromPoints as getBoundsFromPoints4 } from "@tscircuit/math-utils";
14502
- var MIN_EFFECTIVE_BORDER_RADIUS_MM = 0.01;
14503
- var getRoundedRectOutline = (width, height, radius) => {
14504
- const w2 = width / 2;
14505
- const h2 = height / 2;
14506
- const r = Math.min(radius, w2, h2);
14507
- if (r < MIN_EFFECTIVE_BORDER_RADIUS_MM) {
14508
- return [
14509
- { x: -w2, y: -h2 },
14510
- { x: w2, y: -h2 },
14511
- { x: w2, y: h2 },
14512
- { x: -w2, y: h2 }
14513
- ];
14514
- }
14515
- const maxArcLengthPerSegment = 0.1;
14516
- const segments = Math.max(
14517
- 1,
14518
- Math.ceil(Math.PI / 2 * r / maxArcLengthPerSegment)
14519
- );
14520
- const step = Math.PI / 2 / segments;
14521
- const outline = [];
14522
- outline.push({ x: -w2 + r, y: -h2 });
14523
- outline.push({ x: w2 - r, y: -h2 });
14524
- for (let i = 1; i <= segments; i++) {
14525
- const theta = -Math.PI / 2 + i * step;
14526
- outline.push({
14527
- x: w2 - r + r * Math.cos(theta),
14528
- y: -h2 + r + r * Math.sin(theta)
14529
- });
14530
- }
14531
- outline.push({ x: w2, y: h2 - r });
14532
- for (let i = 1; i <= segments; i++) {
14533
- const theta = 0 + i * step;
14534
- outline.push({
14535
- x: w2 - r + r * Math.cos(theta),
14536
- y: h2 - r + r * Math.sin(theta)
14537
- });
14538
- }
14539
- outline.push({ x: -w2 + r, y: h2 });
14540
- for (let i = 1; i <= segments; i++) {
14541
- const theta = Math.PI / 2 + i * step;
14542
- outline.push({
14543
- x: -w2 + r + r * Math.cos(theta),
14544
- y: h2 - r + r * Math.sin(theta)
14545
- });
14546
- }
14547
- outline.push({ x: -w2, y: -h2 + r });
14548
- for (let i = 1; i <= segments; i++) {
14549
- const theta = Math.PI + i * step;
14550
- outline.push({
14551
- x: -w2 + r + r * Math.cos(theta),
14552
- y: -h2 + r + r * Math.sin(theta)
14553
- });
14554
- }
14555
- return outline;
14556
- };
14557
- var Board = class extends Group6 {
14558
- pcb_board_id = null;
14559
- source_board_id = null;
14560
- _drcChecksComplete = false;
14561
- _connectedSchematicPortPairs = /* @__PURE__ */ new Set();
14562
- get isSubcircuit() {
14563
- return true;
14564
- }
14565
- get isGroup() {
14566
- return true;
14491
+ // lib/utils/circuit-json/inflate-circuit-json.ts
14492
+ import { cju } from "@tscircuit/circuit-json-util";
14493
+
14494
+ // lib/components/normal-components/Capacitor.ts
14495
+ import { capacitorProps } from "@tscircuit/props";
14496
+
14497
+ // lib/utils/constants.ts
14498
+ var stringProxy = new Proxy(
14499
+ {},
14500
+ {
14501
+ get: (target, prop) => prop
14567
14502
  }
14503
+ );
14504
+ var FTYPE = stringProxy;
14505
+ var SCHEMATIC_COMPONENT_OUTLINE_COLOR = "rgba(132, 0, 0)";
14506
+ var SCHEMATIC_COMPONENT_OUTLINE_STROKE_WIDTH = 0.12;
14507
+
14508
+ // lib/components/normal-components/Capacitor.ts
14509
+ import { formatSiUnit } from "format-si-unit";
14510
+ var Capacitor = class extends NormalComponent3 {
14511
+ _adjustSilkscreenTextAutomatically = true;
14512
+ // @ts-ignore (cause the symbolName is string and not fixed)
14568
14513
  get config() {
14569
14514
  return {
14570
- componentName: "Board",
14571
- zodProps: boardProps
14515
+ componentName: "Capacitor",
14516
+ schematicSymbolName: this.props.polarized ? "capacitor_polarized" : this.props.symbolName ?? "capacitor",
14517
+ zodProps: capacitorProps,
14518
+ sourceFtype: FTYPE.simple_capacitor
14572
14519
  };
14573
14520
  }
14574
- get boardThickness() {
14575
- const { _parsedProps: props } = this;
14576
- const pcbX = this._resolvePcbCoordinate(props.pcbX, "pcbX", {
14577
- allowBoardVariables: false
14578
- });
14579
- const pcbY = this._resolvePcbCoordinate(props.pcbY, "pcbY", {
14580
- allowBoardVariables: false
14581
- });
14582
- return props.thickness ?? 1.4;
14521
+ initPorts() {
14522
+ if (typeof this.props.footprint === "string") {
14523
+ super.initPorts({
14524
+ additionalAliases: {
14525
+ pin1: ["anode", "pos"],
14526
+ pin2: ["cathode", "neg"]
14527
+ }
14528
+ });
14529
+ } else {
14530
+ super.initPorts();
14531
+ }
14583
14532
  }
14584
- /**
14585
- * Get all available layers for the board
14586
- */
14587
- get allLayers() {
14588
- const layerCount = this._parsedProps.layers ?? 2;
14589
- if (layerCount === 4) {
14590
- return ["top", "bottom", "inner1", "inner2"];
14533
+ _getSchematicSymbolDisplayValue() {
14534
+ const inputCapacitance = this.props.capacitance;
14535
+ const capacitanceDisplay = typeof inputCapacitance === "string" ? inputCapacitance : `${formatSiUnit(this._parsedProps.capacitance)}F`;
14536
+ if (this._parsedProps.schShowRatings && this._parsedProps.maxVoltageRating) {
14537
+ return `${capacitanceDisplay}/${formatSiUnit(this._parsedProps.maxVoltageRating)}V`;
14591
14538
  }
14592
- return ["top", "bottom"];
14539
+ return capacitanceDisplay;
14593
14540
  }
14594
- _getSubcircuitLayerCount() {
14595
- return this._parsedProps.layers ?? 2;
14541
+ doInitialCreateNetsFromProps() {
14542
+ this._createNetsFromProps([
14543
+ this.props.decouplingFor,
14544
+ this.props.decouplingTo,
14545
+ ...this._getNetsFromConnectionsProp()
14546
+ ]);
14596
14547
  }
14597
- _getBoardCalcVariables() {
14598
- const { _parsedProps: props } = this;
14599
- const isAutoSized = (props.width == null || props.height == null) && !props.outline;
14600
- if (isAutoSized) return {};
14601
- const dbBoard = this.pcb_board_id ? this.root?.db.pcb_board.get(this.pcb_board_id) : null;
14602
- let width = dbBoard?.width ?? props.width;
14603
- let height = dbBoard?.height ?? props.height;
14604
- if ((width == null || height == null) && props.outline?.length) {
14605
- const outlineBounds = getBoundsFromPoints4(props.outline);
14606
- if (outlineBounds) {
14607
- width ??= outlineBounds.maxX - outlineBounds.minX;
14608
- height ??= outlineBounds.maxY - outlineBounds.minY;
14609
- }
14548
+ doInitialCreateTracesFromProps() {
14549
+ if (this.props.decouplingFor && this.props.decouplingTo) {
14550
+ this.add(
14551
+ new Trace3({
14552
+ from: `${this.getSubcircuitSelector()} > port.1`,
14553
+ to: this.props.decouplingFor
14554
+ })
14555
+ );
14556
+ this.add(
14557
+ new Trace3({
14558
+ from: `${this.getSubcircuitSelector()} > port.2`,
14559
+ to: this.props.decouplingTo
14560
+ })
14561
+ );
14610
14562
  }
14611
- const { pcbX, pcbY } = this.getResolvedPcbPositionProp();
14612
- const center = dbBoard?.center ?? {
14613
- x: pcbX + (props.outlineOffsetX ?? 0),
14614
- y: pcbY + (props.outlineOffsetY ?? 0)
14615
- };
14616
- const resolvedWidth = width ?? 0;
14617
- const resolvedHeight = height ?? 0;
14618
- return {
14619
- "board.minx": center.x - resolvedWidth / 2,
14620
- "board.maxx": center.x + resolvedWidth / 2,
14621
- "board.miny": center.y - resolvedHeight / 2,
14622
- "board.maxy": center.y + resolvedHeight / 2
14623
- };
14563
+ this._createTracesFromConnectionsProp();
14624
14564
  }
14625
- doInitialPcbBoardAutoSize() {
14626
- if (this.root?.pcbDisabled) return;
14627
- if (!this.pcb_board_id) return;
14565
+ doInitialSourceRender() {
14628
14566
  const { db } = this.root;
14629
14567
  const { _parsedProps: props } = this;
14630
- const pcbX = this._resolvePcbCoordinate(props.pcbX, "pcbX", {
14631
- allowBoardVariables: false
14632
- });
14633
- const pcbY = this._resolvePcbCoordinate(props.pcbY, "pcbY", {
14634
- allowBoardVariables: false
14568
+ const source_component = db.source_component.insert({
14569
+ ftype: "simple_capacitor",
14570
+ name: this.name,
14571
+ // @ts-ignore
14572
+ manufacturer_part_number: props.manufacturerPartNumber ?? props.mfn,
14573
+ supplier_part_numbers: props.supplierPartNumbers,
14574
+ capacitance: props.capacitance,
14575
+ max_voltage_rating: props.maxVoltageRating,
14576
+ max_decoupling_trace_length: props.maxDecouplingTraceLength,
14577
+ display_capacitance: this._getSchematicSymbolDisplayValue(),
14578
+ are_pins_interchangeable: !props.polarized
14635
14579
  });
14636
- if (props.width && props.height || props.outline) return;
14637
- let minX = Infinity;
14638
- let minY = Infinity;
14639
- let maxX = -Infinity;
14640
- let maxY = -Infinity;
14641
- const descendantIds = getDescendantSubcircuitIds(db, this.subcircuit_id);
14642
- const allowedSubcircuitIds = /* @__PURE__ */ new Set([this.subcircuit_id, ...descendantIds]);
14643
- const allPcbComponents = db.pcb_component.list().filter(
14644
- (c) => c.subcircuit_id && allowedSubcircuitIds.has(c.subcircuit_id)
14645
- );
14646
- const allPcbGroups = db.pcb_group.list().filter(
14647
- (g) => g.subcircuit_id && allowedSubcircuitIds.has(g.subcircuit_id)
14648
- );
14649
- let hasComponents = false;
14650
- const updateBounds = (center2, width, height) => {
14651
- if (width === 0 || height === 0) return;
14652
- hasComponents = true;
14653
- minX = Math.min(minX, center2.x - width / 2);
14654
- minY = Math.min(minY, center2.y - height / 2);
14655
- maxX = Math.max(maxX, center2.x + width / 2);
14656
- maxY = Math.max(maxY, center2.y + height / 2);
14657
- };
14658
- for (const pcbComponent of allPcbComponents) {
14659
- updateBounds(pcbComponent.center, pcbComponent.width, pcbComponent.height);
14660
- }
14661
- for (const pcbGroup of allPcbGroups) {
14662
- let width = pcbGroup.width ?? 0;
14663
- let height = pcbGroup.height ?? 0;
14664
- if (pcbGroup.outline && pcbGroup.outline.length > 0) {
14665
- const bounds = getBoundsFromPoints4(pcbGroup.outline);
14666
- if (bounds) {
14667
- width = bounds.maxX - bounds.minX;
14668
- height = bounds.maxY - bounds.minY;
14669
- }
14670
- }
14671
- updateBounds(pcbGroup.center, width, height);
14672
- }
14673
- if (props.boardAnchorPosition) {
14674
- const { x, y } = props.boardAnchorPosition;
14675
- minX = Math.min(minX, x);
14676
- minY = Math.min(minY, y);
14677
- maxX = Math.max(maxX, x);
14678
- maxY = Math.max(maxY, y);
14679
- }
14680
- const padding = 2;
14681
- const computedWidth = hasComponents ? maxX - minX + padding * 2 : 0;
14682
- const computedHeight = hasComponents ? maxY - minY + padding * 2 : 0;
14683
- const center = {
14684
- x: hasComponents ? (minX + maxX) / 2 + (props.outlineOffsetX ?? 0) : (props.outlineOffsetX ?? 0) + pcbX,
14685
- y: hasComponents ? (minY + maxY) / 2 + (props.outlineOffsetY ?? 0) : (props.outlineOffsetY ?? 0) + pcbY
14686
- };
14687
- const finalWidth = props.width ?? computedWidth;
14688
- const finalHeight = props.height ?? computedHeight;
14689
- let outline = props.outline;
14690
- if (!outline && props.borderRadius != null && finalWidth > 0 && finalHeight > 0) {
14691
- outline = getRoundedRectOutline(
14692
- finalWidth,
14693
- finalHeight,
14694
- props.borderRadius
14695
- );
14696
- }
14697
- const update = {
14698
- width: finalWidth,
14699
- height: finalHeight,
14700
- center
14701
- };
14702
- if (outline) {
14703
- update.outline = outline.map((point) => ({
14704
- x: point.x + (props.outlineOffsetX ?? 0),
14705
- y: point.y + (props.outlineOffsetY ?? 0)
14706
- }));
14707
- }
14708
- db.pcb_board.update(this.pcb_board_id, update);
14580
+ this.source_component_id = source_component.source_component_id;
14709
14581
  }
14710
- // Recompute autosize after child components update (e.g., async footprints)
14711
- updatePcbBoardAutoSize() {
14712
- this.doInitialPcbBoardAutoSize();
14582
+ };
14583
+
14584
+ // lib/components/primitive-components/Group/Subcircuit/inflators/inflatePcbComponent.ts
14585
+ import { compose as compose5, translate as translate6, rotate as rotate3, inverse } from "transformation-matrix";
14586
+ import { transformPCBElements as transformPCBElements2 } from "@tscircuit/circuit-json-util";
14587
+ var inflatePcbComponent = (pcbElm, inflatorContext) => {
14588
+ const { injectionDb, normalComponent } = inflatorContext;
14589
+ if (!normalComponent) return;
14590
+ const componentCenter = pcbElm.center || { x: 0, y: 0 };
14591
+ const componentRotation = pcbElm.rotation || 0;
14592
+ const absoluteToComponentRelativeTransform = inverse(
14593
+ compose5(
14594
+ translate6(componentCenter.x, componentCenter.y),
14595
+ rotate3(componentRotation * Math.PI / 180)
14596
+ )
14597
+ );
14598
+ const relativeElements = injectionDb.toArray().filter(
14599
+ (elm) => "pcb_component_id" in elm && elm.pcb_component_id === pcbElm.pcb_component_id
14600
+ );
14601
+ transformPCBElements2(relativeElements, absoluteToComponentRelativeTransform);
14602
+ const components = createComponentsFromCircuitJson(
14603
+ {
14604
+ componentName: normalComponent.name,
14605
+ componentRotation: "0deg"
14606
+ },
14607
+ relativeElements
14608
+ );
14609
+ normalComponent.addAll(components);
14610
+ };
14611
+
14612
+ // lib/components/primitive-components/Group/Subcircuit/inflators/inflateSourceCapacitor.ts
14613
+ function inflateSourceCapacitor(sourceElm, inflatorContext) {
14614
+ const { injectionDb, subcircuit, groupsMap } = inflatorContext;
14615
+ const pcbElm = injectionDb.pcb_component.getWhere({
14616
+ source_component_id: sourceElm.source_component_id
14617
+ });
14618
+ const cadElm = injectionDb.cad_component.getWhere({
14619
+ source_component_id: sourceElm.source_component_id
14620
+ });
14621
+ const capacitor = new Capacitor({
14622
+ name: sourceElm.name,
14623
+ capacitance: sourceElm.capacitance,
14624
+ layer: pcbElm?.layer,
14625
+ pcbX: pcbElm?.center?.x,
14626
+ pcbY: pcbElm?.center?.y,
14627
+ pcbRotation: pcbElm?.rotation,
14628
+ doNotPlace: pcbElm?.do_not_place,
14629
+ obstructsWithinBounds: pcbElm?.obstructs_within_bounds
14630
+ });
14631
+ if (pcbElm) {
14632
+ inflatePcbComponent(pcbElm, {
14633
+ ...inflatorContext,
14634
+ normalComponent: capacitor
14635
+ });
14713
14636
  }
14714
- /**
14715
- * Update the board information silkscreen text if platform config is set and
14716
- * the project name, version, or url is set.
14717
- */
14718
- _addBoardInformationToSilkscreen() {
14719
- const platform = this.root?.platform;
14720
- if (!platform?.printBoardInformationToSilkscreen) return;
14721
- const pcbBoard = this.root.db.pcb_board.get(this.pcb_board_id);
14722
- if (!pcbBoard) return;
14723
- const boardInformation = [];
14724
- if (platform.projectName) boardInformation.push(platform.projectName);
14725
- if (platform.version) boardInformation.push(`v${platform.version}`);
14726
- if (platform.url) boardInformation.push(platform.url);
14727
- if (boardInformation.length === 0) return;
14728
- const text = boardInformation.join("\n");
14729
- const marginX = 0.25;
14730
- const marginY = 1;
14731
- const position = {
14732
- x: pcbBoard.center.x + pcbBoard.width / 2 - marginX,
14733
- y: pcbBoard.center.y - pcbBoard.height / 2 + marginY
14637
+ if (sourceElm.source_group_id && groupsMap?.has(sourceElm.source_group_id)) {
14638
+ const group = groupsMap.get(sourceElm.source_group_id);
14639
+ group.add(capacitor);
14640
+ } else {
14641
+ subcircuit.add(capacitor);
14642
+ }
14643
+ }
14644
+
14645
+ // lib/components/normal-components/Chip.ts
14646
+ import { chipProps as chipProps2 } from "@tscircuit/props";
14647
+ import { pcb_component_invalid_layer_error as pcb_component_invalid_layer_error2 } from "circuit-json";
14648
+ var Chip = class extends NormalComponent3 {
14649
+ schematicBoxDimensions = null;
14650
+ constructor(props) {
14651
+ super(props);
14652
+ }
14653
+ get config() {
14654
+ return {
14655
+ componentName: "Chip",
14656
+ zodProps: chipProps2,
14657
+ shouldRenderAsSchematicBox: true
14734
14658
  };
14735
- this.root.db.pcb_silkscreen_text.insert({
14736
- pcb_component_id: this.pcb_board_id,
14737
- layer: "top",
14738
- font: "tscircuit2024",
14739
- font_size: 0.45,
14740
- text,
14741
- ccw_rotation: 0,
14742
- anchor_alignment: "bottom_right",
14743
- anchor_position: position
14744
- });
14659
+ }
14660
+ initPorts(opts = {}) {
14661
+ super.initPorts(opts);
14662
+ const { _parsedProps: props } = this;
14663
+ const { pcbX, pcbY } = this.getResolvedPcbPositionProp();
14664
+ if (props.externallyConnectedPins) {
14665
+ const requiredPorts = /* @__PURE__ */ new Set();
14666
+ for (const [pin1, pin2] of props.externallyConnectedPins) {
14667
+ requiredPorts.add(pin1);
14668
+ requiredPorts.add(pin2);
14669
+ }
14670
+ for (const pinIdentifier of requiredPorts) {
14671
+ const existingPort = this.children.find(
14672
+ (child) => child instanceof Port && child.isMatchingAnyOf([pinIdentifier])
14673
+ );
14674
+ if (!existingPort) {
14675
+ const pinMatch = pinIdentifier.match(/^pin(\d+)$/);
14676
+ if (pinMatch) {
14677
+ const pinNumber = parseInt(pinMatch[1]);
14678
+ this.add(
14679
+ new Port({
14680
+ pinNumber,
14681
+ aliases: [pinIdentifier]
14682
+ })
14683
+ );
14684
+ } else {
14685
+ this.add(
14686
+ new Port({
14687
+ name: pinIdentifier,
14688
+ aliases: [pinIdentifier]
14689
+ })
14690
+ );
14691
+ }
14692
+ }
14693
+ }
14694
+ }
14695
+ }
14696
+ doInitialSchematicComponentRender() {
14697
+ const { _parsedProps: props } = this;
14698
+ if (props?.noSchematicRepresentation === true) return;
14699
+ super.doInitialSchematicComponentRender();
14745
14700
  }
14746
14701
  doInitialSourceRender() {
14747
- super.doInitialSourceRender();
14748
14702
  const { db } = this.root;
14749
- const source_board = db.source_board.insert({
14750
- source_group_id: this.source_group_id,
14751
- title: this.props.title || this.props.name
14703
+ const { _parsedProps: props } = this;
14704
+ const { pcbX, pcbY } = this.getResolvedPcbPositionProp();
14705
+ const source_component = db.source_component.insert({
14706
+ ftype: "simple_chip",
14707
+ name: this.name,
14708
+ manufacturer_part_number: props.manufacturerPartNumber,
14709
+ supplier_part_numbers: props.supplierPartNumbers
14752
14710
  });
14753
- this.source_board_id = source_board.source_board_id;
14711
+ this.source_component_id = source_component.source_component_id;
14754
14712
  }
14755
14713
  doInitialPcbComponentRender() {
14756
14714
  if (this.root?.pcbDisabled) return;
14757
14715
  const { db } = this.root;
14758
14716
  const { _parsedProps: props } = this;
14759
- let computedWidth = props.width ?? 0;
14760
- let computedHeight = props.height ?? 0;
14761
14717
  const { pcbX, pcbY } = this.getResolvedPcbPositionProp();
14762
- let center = {
14763
- x: pcbX + (props.outlineOffsetX ?? 0),
14764
- y: pcbY + (props.outlineOffsetY ?? 0)
14765
- };
14766
- const { boardAnchorPosition, boardAnchorAlignment } = props;
14767
- if (boardAnchorPosition) {
14768
- center = getBoardCenterFromAnchor({
14769
- boardAnchorPosition,
14770
- boardAnchorAlignment: boardAnchorAlignment ?? "center",
14771
- width: computedWidth,
14772
- height: computedHeight
14718
+ const componentLayer = props.layer ?? "top";
14719
+ if (componentLayer !== "top" && componentLayer !== "bottom") {
14720
+ const subcircuit = this.getSubcircuit();
14721
+ const error = pcb_component_invalid_layer_error2.parse({
14722
+ type: "pcb_component_invalid_layer_error",
14723
+ message: `Component cannot be placed on layer '${componentLayer}'. Components can only be placed on 'top' or 'bottom' layers.`,
14724
+ source_component_id: this.source_component_id,
14725
+ layer: componentLayer,
14726
+ subcircuit_id: subcircuit.subcircuit_id ?? void 0
14773
14727
  });
14728
+ db.pcb_component_invalid_layer_error.insert(error);
14774
14729
  }
14775
- if (props.outline) {
14776
- const xValues = props.outline.map((point) => point.x);
14777
- const yValues = props.outline.map((point) => point.y);
14778
- const minX = Math.min(...xValues);
14779
- const maxX = Math.max(...xValues);
14780
- const minY = Math.min(...yValues);
14781
- const maxY = Math.max(...yValues);
14782
- computedWidth = maxX - minX;
14783
- computedHeight = maxY - minY;
14784
- center = {
14785
- x: (minX + maxX) / 2 + (props.outlineOffsetX ?? 0),
14786
- y: (minY + maxY) / 2 + (props.outlineOffsetY ?? 0)
14787
- };
14788
- }
14789
- let outline = props.outline;
14790
- if (!outline && props.borderRadius != null && computedWidth > 0 && computedHeight > 0) {
14791
- outline = getRoundedRectOutline(
14792
- computedWidth,
14793
- computedHeight,
14794
- props.borderRadius
14795
- );
14796
- }
14797
- const pcb_board = db.pcb_board.insert({
14798
- center,
14799
- thickness: this.boardThickness,
14800
- num_layers: this.allLayers.length,
14801
- width: computedWidth,
14802
- height: computedHeight,
14803
- outline: outline?.map((point) => ({
14804
- x: point.x + (props.outlineOffsetX ?? 0),
14805
- y: point.y + (props.outlineOffsetY ?? 0)
14806
- })),
14807
- material: props.material
14730
+ const pcb_component = db.pcb_component.insert({
14731
+ center: { x: pcbX, y: pcbY },
14732
+ width: 2,
14733
+ // Default width, adjust as needed
14734
+ height: 3,
14735
+ // Default height, adjust as needed
14736
+ layer: componentLayer === "top" || componentLayer === "bottom" ? componentLayer : "top",
14737
+ rotation: props.pcbRotation ?? 0,
14738
+ source_component_id: this.source_component_id,
14739
+ subcircuit_id: this.getSubcircuit().subcircuit_id ?? void 0,
14740
+ do_not_place: props.doNotPlace ?? false,
14741
+ obstructs_within_bounds: props.obstructsWithinBounds ?? true
14808
14742
  });
14809
- this.pcb_board_id = pcb_board.pcb_board_id;
14810
- this._addBoardInformationToSilkscreen();
14743
+ this.pcb_component_id = pcb_component.pcb_component_id;
14744
+ }
14745
+ doInitialCreateTracesFromProps() {
14746
+ const { _parsedProps: props } = this;
14747
+ if (props.externallyConnectedPins) {
14748
+ for (const [pin1, pin2] of props.externallyConnectedPins) {
14749
+ this.add(
14750
+ new Trace3({
14751
+ from: `${this.getSubcircuitSelector()} > port.${pin1}`,
14752
+ to: `${this.getSubcircuitSelector()} > port.${pin2}`
14753
+ })
14754
+ );
14755
+ }
14756
+ }
14757
+ this._createTracesFromConnectionsProp();
14758
+ }
14759
+ doInitialSimulationRender() {
14760
+ const { db } = this.root;
14761
+ const { pinAttributes } = this.props;
14762
+ if (!pinAttributes) return;
14763
+ let powerPort = null;
14764
+ let groundPort = null;
14765
+ let voltage;
14766
+ const ports = this.selectAll("port");
14767
+ for (const port of ports) {
14768
+ for (const alias of port.getNameAndAliases()) {
14769
+ if (pinAttributes[alias]) {
14770
+ const attributes = pinAttributes[alias];
14771
+ if (attributes.providesPower) {
14772
+ powerPort = port;
14773
+ voltage = attributes.providesVoltage;
14774
+ }
14775
+ if (attributes.providesGround) {
14776
+ groundPort = port;
14777
+ }
14778
+ }
14779
+ }
14780
+ }
14781
+ if (!powerPort || !groundPort || voltage === void 0) {
14782
+ return;
14783
+ }
14784
+ const powerSourcePort = db.source_port.get(powerPort.source_port_id);
14785
+ if (!powerSourcePort?.subcircuit_connectivity_map_key) return;
14786
+ const groundSourcePort = db.source_port.get(groundPort.source_port_id);
14787
+ if (!groundSourcePort?.subcircuit_connectivity_map_key) return;
14788
+ const powerNet = db.source_net.getWhere({
14789
+ subcircuit_connectivity_map_key: powerSourcePort.subcircuit_connectivity_map_key
14790
+ });
14791
+ const groundNet = db.source_net.getWhere({
14792
+ subcircuit_connectivity_map_key: groundSourcePort.subcircuit_connectivity_map_key
14793
+ });
14794
+ if (!powerNet || !groundNet) {
14795
+ return;
14796
+ }
14797
+ ;
14798
+ db.simulation_voltage_source.insert({
14799
+ type: "simulation_voltage_source",
14800
+ positive_source_port_id: powerPort.source_port_id,
14801
+ positive_source_net_id: powerNet.source_net_id,
14802
+ negative_source_port_id: groundPort.source_port_id,
14803
+ negative_source_net_id: groundNet.source_net_id,
14804
+ voltage
14805
+ });
14806
+ }
14807
+ };
14808
+
14809
+ // lib/components/primitive-components/Group/Subcircuit/inflators/inflateSourceChip.ts
14810
+ var mapInternallyConnectedSourcePortIdsToPinLabels = (sourcePortIds, inflatorContext) => {
14811
+ if (!sourcePortIds || sourcePortIds.length === 0) return void 0;
14812
+ const { injectionDb } = inflatorContext;
14813
+ const mapped = sourcePortIds.map(
14814
+ (group) => group.map((sourcePortId) => {
14815
+ const port = injectionDb.source_port.get(
14816
+ sourcePortId
14817
+ );
14818
+ if (!port) return null;
14819
+ if (port.pin_number !== void 0 && port.pin_number !== null) {
14820
+ return `pin${port.pin_number}`;
14821
+ }
14822
+ return port.name;
14823
+ }).filter((value) => value !== null)
14824
+ ).filter((group) => group.length > 0);
14825
+ return mapped.length > 0 ? mapped : void 0;
14826
+ };
14827
+ var inflateSourceChip = (sourceElm, inflatorContext) => {
14828
+ const { injectionDb, subcircuit, groupsMap } = inflatorContext;
14829
+ const pcbElm = injectionDb.pcb_component.getWhere({
14830
+ source_component_id: sourceElm.source_component_id
14831
+ });
14832
+ const schematicElm = injectionDb.schematic_component.getWhere({
14833
+ source_component_id: sourceElm.source_component_id
14834
+ });
14835
+ const cadElm = injectionDb.cad_component.getWhere({
14836
+ source_component_id: sourceElm.source_component_id
14837
+ });
14838
+ const internallyConnectedPins = mapInternallyConnectedSourcePortIdsToPinLabels(
14839
+ sourceElm.internally_connected_source_port_ids,
14840
+ inflatorContext
14841
+ );
14842
+ const chip = new Chip({
14843
+ name: sourceElm.name,
14844
+ manufacturerPartNumber: sourceElm.manufacturer_part_number,
14845
+ supplierPartNumbers: sourceElm.supplier_part_numbers ?? void 0,
14846
+ pinLabels: schematicElm?.port_labels ?? void 0,
14847
+ schWidth: schematicElm?.size?.width,
14848
+ schHeight: schematicElm?.size?.height,
14849
+ schPinSpacing: schematicElm?.pin_spacing,
14850
+ schX: schematicElm?.center?.x,
14851
+ schY: schematicElm?.center?.y,
14852
+ layer: pcbElm?.layer,
14853
+ pcbX: pcbElm?.center?.x,
14854
+ pcbY: pcbElm?.center?.y,
14855
+ pcbRotation: pcbElm?.rotation,
14856
+ doNotPlace: pcbElm?.do_not_place,
14857
+ obstructsWithinBounds: pcbElm?.obstructs_within_bounds,
14858
+ internallyConnectedPins
14859
+ });
14860
+ const footprint = cadElm?.footprinter_string ?? null;
14861
+ if (footprint) {
14862
+ Object.assign(chip.props, { footprint });
14863
+ Object.assign(chip._parsedProps, { footprint });
14864
+ if (!cadElm) {
14865
+ ;
14866
+ chip._addChildrenFromStringFootprint?.();
14867
+ }
14868
+ }
14869
+ if (pcbElm) {
14870
+ inflatePcbComponent(pcbElm, {
14871
+ ...inflatorContext,
14872
+ normalComponent: chip
14873
+ });
14874
+ }
14875
+ if (sourceElm.source_group_id && groupsMap?.has(sourceElm.source_group_id)) {
14876
+ const group = groupsMap.get(sourceElm.source_group_id);
14877
+ group.add(chip);
14878
+ } else {
14879
+ subcircuit.add(chip);
14880
+ }
14881
+ };
14882
+
14883
+ // lib/components/normal-components/Diode.ts
14884
+ import { diodeProps } from "@tscircuit/props";
14885
+ var Diode = class extends NormalComponent3 {
14886
+ // @ts-ignore
14887
+ get config() {
14888
+ const symbolMap = {
14889
+ schottky: "schottky_diode",
14890
+ avalanche: "avalanche_diode",
14891
+ zener: "zener_diode",
14892
+ photodiode: "photodiode"
14893
+ };
14894
+ const variantSymbol = this.props.schottky ? "schottky" : this.props.avalanche ? "avalanche" : this.props.zener ? "zener" : this.props.photo ? "photodiode" : null;
14895
+ return {
14896
+ schematicSymbolName: variantSymbol ? symbolMap[variantSymbol] : this.props.symbolName ?? "diode",
14897
+ componentName: "Diode",
14898
+ zodProps: diodeProps,
14899
+ sourceFtype: "simple_diode"
14900
+ };
14901
+ }
14902
+ initPorts() {
14903
+ super.initPorts({
14904
+ additionalAliases: {
14905
+ pin1: ["anode", "pos", "left"],
14906
+ pin2: ["cathode", "neg", "right"]
14907
+ }
14908
+ });
14909
+ }
14910
+ doInitialSourceRender() {
14911
+ const { db } = this.root;
14912
+ const { _parsedProps: props } = this;
14913
+ const source_component = db.source_component.insert({
14914
+ ftype: "simple_diode",
14915
+ name: this.name,
14916
+ // @ts-ignore
14917
+ manufacturer_part_number: props.manufacturerPartNumber ?? props.mfn,
14918
+ supplier_part_numbers: props.supplierPartNumbers,
14919
+ are_pins_interchangeable: false
14920
+ });
14921
+ this.source_component_id = source_component.source_component_id;
14922
+ }
14923
+ pos = this.portMap.pin1;
14924
+ anode = this.portMap.pin1;
14925
+ neg = this.portMap.pin2;
14926
+ cathode = this.portMap.pin2;
14927
+ };
14928
+
14929
+ // lib/components/primitive-components/Group/Subcircuit/inflators/inflateSourceDiode.ts
14930
+ function inflateSourceDiode(sourceElm, inflatorContext) {
14931
+ const { injectionDb, subcircuit, groupsMap } = inflatorContext;
14932
+ const pcbElm = injectionDb.pcb_component.getWhere({
14933
+ source_component_id: sourceElm.source_component_id
14934
+ });
14935
+ const cadElm = injectionDb.cad_component.getWhere({
14936
+ source_component_id: sourceElm.source_component_id
14937
+ });
14938
+ const diode = new Diode({
14939
+ name: sourceElm.name,
14940
+ layer: pcbElm?.layer,
14941
+ pcbX: pcbElm?.center?.x,
14942
+ pcbY: pcbElm?.center?.y,
14943
+ pcbRotation: pcbElm?.rotation,
14944
+ doNotPlace: pcbElm?.do_not_place,
14945
+ obstructsWithinBounds: pcbElm?.obstructs_within_bounds
14946
+ });
14947
+ if (pcbElm) {
14948
+ inflatePcbComponent(pcbElm, {
14949
+ ...inflatorContext,
14950
+ normalComponent: diode
14951
+ });
14952
+ }
14953
+ if (sourceElm.source_group_id && groupsMap?.has(sourceElm.source_group_id)) {
14954
+ const group = groupsMap.get(sourceElm.source_group_id);
14955
+ group.add(diode);
14956
+ } else {
14957
+ subcircuit.add(diode);
14958
+ }
14959
+ }
14960
+
14961
+ // lib/components/primitive-components/Group/Subcircuit/inflators/inflateSourceGroup.ts
14962
+ function inflateSourceGroup(sourceGroup, inflatorContext) {
14963
+ const { subcircuit, groupsMap } = inflatorContext;
14964
+ const group = new Group6({
14965
+ name: sourceGroup.name
14966
+ });
14967
+ group.source_group_id = sourceGroup.source_group_id;
14968
+ subcircuit.add(group);
14969
+ if (groupsMap) {
14970
+ groupsMap.set(sourceGroup.source_group_id, group);
14971
+ }
14972
+ return group;
14973
+ }
14974
+
14975
+ // lib/components/normal-components/Inductor.ts
14976
+ import { inductorProps } from "@tscircuit/props";
14977
+ import { formatSiUnit as formatSiUnit2 } from "format-si-unit";
14978
+ var Inductor = class extends NormalComponent3 {
14979
+ _adjustSilkscreenTextAutomatically = true;
14980
+ get config() {
14981
+ return {
14982
+ componentName: "Inductor",
14983
+ schematicSymbolName: this.props.symbolName ?? "inductor",
14984
+ zodProps: inductorProps,
14985
+ sourceFtype: FTYPE.simple_inductor
14986
+ };
14987
+ }
14988
+ _getSchematicSymbolDisplayValue() {
14989
+ return `${formatSiUnit2(this._parsedProps.inductance)}H`;
14990
+ }
14991
+ initPorts() {
14992
+ super.initPorts({
14993
+ additionalAliases: {
14994
+ pin1: ["anode", "pos", "left"],
14995
+ pin2: ["cathode", "neg", "right"]
14996
+ }
14997
+ });
14998
+ }
14999
+ doInitialSourceRender() {
15000
+ const { db } = this.root;
15001
+ const { _parsedProps: props } = this;
15002
+ const source_component = db.source_component.insert({
15003
+ name: this.name,
15004
+ ftype: FTYPE.simple_inductor,
15005
+ inductance: props.inductance,
15006
+ supplier_part_numbers: props.supplierPartNumbers,
15007
+ are_pins_interchangeable: true
15008
+ });
15009
+ this.source_component_id = source_component.source_component_id;
15010
+ }
15011
+ };
15012
+
15013
+ // lib/components/primitive-components/Group/Subcircuit/inflators/inflateSourceInductor.ts
15014
+ function inflateSourceInductor(sourceElm, inflatorContext) {
15015
+ const { injectionDb, subcircuit, groupsMap } = inflatorContext;
15016
+ const pcbElm = injectionDb.pcb_component.getWhere({
15017
+ source_component_id: sourceElm.source_component_id
15018
+ });
15019
+ const cadElm = injectionDb.cad_component.getWhere({
15020
+ source_component_id: sourceElm.source_component_id
15021
+ });
15022
+ const inductor = new Inductor({
15023
+ name: sourceElm.name,
15024
+ inductance: sourceElm.inductance,
15025
+ layer: pcbElm?.layer,
15026
+ pcbX: pcbElm?.center?.x,
15027
+ pcbY: pcbElm?.center?.y,
15028
+ pcbRotation: pcbElm?.rotation,
15029
+ doNotPlace: pcbElm?.do_not_place,
15030
+ obstructsWithinBounds: pcbElm?.obstructs_within_bounds
15031
+ });
15032
+ if (pcbElm) {
15033
+ inflatePcbComponent(pcbElm, {
15034
+ ...inflatorContext,
15035
+ normalComponent: inductor
15036
+ });
15037
+ }
15038
+ if (sourceElm.source_group_id && groupsMap?.has(sourceElm.source_group_id)) {
15039
+ const group = groupsMap.get(sourceElm.source_group_id);
15040
+ group.add(inductor);
15041
+ } else {
15042
+ subcircuit.add(inductor);
15043
+ }
15044
+ }
15045
+
15046
+ // lib/components/primitive-components/Group/Subcircuit/inflators/inflateSourcePort.ts
15047
+ function inflateSourcePort(sourcePort, inflatorContext) {
15048
+ const { injectionDb, subcircuit } = inflatorContext;
15049
+ if (sourcePort.source_component_id !== null) {
15050
+ return;
15051
+ }
15052
+ const pcbPortFromInjection = injectionDb.pcb_port.getWhere({
15053
+ source_port_id: sourcePort.source_port_id
15054
+ });
15055
+ const port = new Port({
15056
+ name: sourcePort.name,
15057
+ pinNumber: sourcePort.pin_number
15058
+ });
15059
+ subcircuit.add(port);
15060
+ port.source_port_id = sourcePort.source_port_id;
15061
+ const root = subcircuit.root;
15062
+ if (root && pcbPortFromInjection) {
15063
+ const { db } = root;
15064
+ const pcb_port = db.pcb_port.insert({
15065
+ pcb_component_id: void 0,
15066
+ layers: pcbPortFromInjection.layers,
15067
+ subcircuit_id: subcircuit.subcircuit_id ?? void 0,
15068
+ pcb_group_id: subcircuit.getGroup()?.pcb_group_id ?? void 0,
15069
+ x: pcbPortFromInjection.x,
15070
+ y: pcbPortFromInjection.y,
15071
+ source_port_id: sourcePort.source_port_id,
15072
+ is_board_pinout: false
15073
+ });
15074
+ port.pcb_port_id = pcb_port.pcb_port_id;
15075
+ }
15076
+ }
15077
+
15078
+ // lib/components/normal-components/Resistor.ts
15079
+ import { resistorProps } from "@tscircuit/props";
15080
+ import { formatSiUnit as formatSiUnit3 } from "format-si-unit";
15081
+ var Resistor = class extends NormalComponent3 {
15082
+ _adjustSilkscreenTextAutomatically = true;
15083
+ get config() {
15084
+ return {
15085
+ componentName: "Resistor",
15086
+ schematicSymbolName: this.props.symbolName ?? "boxresistor",
15087
+ zodProps: resistorProps,
15088
+ sourceFtype: "simple_resistor"
15089
+ };
15090
+ }
15091
+ initPorts() {
15092
+ super.initPorts({
15093
+ additionalAliases: {
15094
+ pin1: ["anode", "pos", "left"],
15095
+ pin2: ["cathode", "neg", "right"]
15096
+ }
15097
+ });
15098
+ }
15099
+ _getSchematicSymbolDisplayValue() {
15100
+ return `${formatSiUnit3(this._parsedProps.resistance)}\u03A9`;
15101
+ }
15102
+ doInitialCreateNetsFromProps() {
15103
+ this._createNetsFromProps([
15104
+ this.props.pullupFor,
15105
+ this.props.pullupTo,
15106
+ this.props.pulldownFor,
15107
+ this.props.pulldownTo,
15108
+ ...this._getNetsFromConnectionsProp()
15109
+ ]);
15110
+ }
15111
+ doInitialCreateTracesFromProps() {
15112
+ if (this.props.pullupFor && this.props.pullupTo) {
15113
+ this.add(
15114
+ new Trace3({
15115
+ from: `${this.getSubcircuitSelector()} > port.1`,
15116
+ to: this.props.pullupFor
15117
+ })
15118
+ );
15119
+ this.add(
15120
+ new Trace3({
15121
+ from: `${this.getSubcircuitSelector()} > port.2`,
15122
+ to: this.props.pullupTo
15123
+ })
15124
+ );
15125
+ }
15126
+ if (this.props.pulldownFor && this.props.pulldownTo) {
15127
+ this.add(
15128
+ new Trace3({
15129
+ from: `${this.getSubcircuitSelector()} > port.1`,
15130
+ to: this.props.pulldownFor
15131
+ })
15132
+ );
15133
+ this.add(
15134
+ new Trace3({
15135
+ from: `${this.getSubcircuitSelector()} > port.2`,
15136
+ to: this.props.pulldownTo
15137
+ })
15138
+ );
15139
+ }
15140
+ this._createTracesFromConnectionsProp();
15141
+ }
15142
+ doInitialSourceRender() {
15143
+ const { db } = this.root;
15144
+ const { _parsedProps: props } = this;
15145
+ const source_component = db.source_component.insert({
15146
+ ftype: "simple_resistor",
15147
+ name: this.name,
15148
+ // @ts-ignore
15149
+ manufacturer_part_number: props.manufacturerPartNumber ?? props.mfn,
15150
+ supplier_part_numbers: props.supplierPartNumbers,
15151
+ resistance: props.resistance,
15152
+ display_resistance: this._getSchematicSymbolDisplayValue(),
15153
+ are_pins_interchangeable: true
15154
+ });
15155
+ this.source_component_id = source_component.source_component_id;
15156
+ }
15157
+ };
15158
+
15159
+ // lib/components/primitive-components/Group/Subcircuit/inflators/inflateSourceResistor.ts
15160
+ function inflateSourceResistor(sourceElm, inflatorContext) {
15161
+ const { injectionDb, subcircuit, groupsMap } = inflatorContext;
15162
+ const pcbElm = injectionDb.pcb_component.getWhere({
15163
+ source_component_id: sourceElm.source_component_id
15164
+ });
15165
+ const cadElm = injectionDb.cad_component.getWhere({
15166
+ source_component_id: sourceElm.source_component_id
15167
+ });
15168
+ const resistor = new Resistor({
15169
+ name: sourceElm.name,
15170
+ resistance: sourceElm.resistance,
15171
+ layer: pcbElm?.layer,
15172
+ pcbX: pcbElm?.center?.x,
15173
+ pcbY: pcbElm?.center?.y,
15174
+ pcbRotation: pcbElm?.rotation,
15175
+ doNotPlace: pcbElm?.do_not_place,
15176
+ obstructsWithinBounds: pcbElm?.obstructs_within_bounds
15177
+ });
15178
+ if (pcbElm) {
15179
+ inflatePcbComponent(pcbElm, {
15180
+ ...inflatorContext,
15181
+ normalComponent: resistor
15182
+ });
15183
+ }
15184
+ if (sourceElm.source_group_id && groupsMap?.has(sourceElm.source_group_id)) {
15185
+ const group = groupsMap.get(sourceElm.source_group_id);
15186
+ group.add(resistor);
15187
+ } else {
15188
+ subcircuit.add(resistor);
15189
+ }
15190
+ }
15191
+
15192
+ // lib/components/primitive-components/Group/Subcircuit/inflators/inflateSourceTrace.ts
15193
+ var getSelectorPath = (component, db) => {
15194
+ const path_parts = [];
15195
+ let currentGroupId = component.source_group_id;
15196
+ while (currentGroupId) {
15197
+ const group = db.source_group.get(currentGroupId);
15198
+ if (!group) break;
15199
+ path_parts.unshift(`.${group.name}`);
15200
+ currentGroupId = group.parent_source_group_id;
15201
+ }
15202
+ path_parts.push(`.${component.name}`);
15203
+ return path_parts.join(" > ");
15204
+ };
15205
+ function inflateSourceTrace(sourceTrace, inflatorContext) {
15206
+ const { injectionDb, subcircuit } = inflatorContext;
15207
+ const connectedSelectors = [];
15208
+ for (const sourcePortId of sourceTrace.connected_source_port_ids) {
15209
+ const sourcePort = injectionDb.source_port.get(sourcePortId);
15210
+ if (!sourcePort) continue;
15211
+ let selector;
15212
+ if (sourcePort.source_component_id) {
15213
+ const sourceComponent = injectionDb.source_component.get(
15214
+ sourcePort.source_component_id
15215
+ );
15216
+ if (sourceComponent) {
15217
+ const path = getSelectorPath(
15218
+ {
15219
+ name: sourceComponent.name,
15220
+ source_group_id: sourceComponent.source_group_id
15221
+ },
15222
+ injectionDb
15223
+ );
15224
+ selector = `${path} > .${sourcePort.name}`;
15225
+ }
15226
+ } else {
15227
+ selector = `.${sourcePort.name}`;
15228
+ }
15229
+ if (selector) {
15230
+ connectedSelectors.push(selector);
15231
+ }
15232
+ }
15233
+ for (const sourceNetId of sourceTrace.connected_source_net_ids) {
15234
+ const sourceNet = injectionDb.source_net.get(sourceNetId);
15235
+ if (sourceNet) {
15236
+ connectedSelectors.push(`net.${sourceNet.name}`);
15237
+ }
15238
+ }
15239
+ if (connectedSelectors.length < 2) return;
15240
+ const trace = new Trace3({
15241
+ path: connectedSelectors
15242
+ });
15243
+ trace.source_trace_id = sourceTrace.source_trace_id;
15244
+ subcircuit.add(trace);
15245
+ }
15246
+
15247
+ // lib/components/normal-components/Transistor.ts
15248
+ import { transistorProps } from "@tscircuit/props";
15249
+ var Transistor = class extends NormalComponent3 {
15250
+ get config() {
15251
+ const baseSymbolName = this.props.type === "npn" ? "npn_bipolar_transistor" : "pnp_bipolar_transistor";
15252
+ return {
15253
+ componentName: "Transistor",
15254
+ schematicSymbolName: this.props.symbolName ?? baseSymbolName,
15255
+ zodProps: transistorProps,
15256
+ sourceFtype: "simple_transistor",
15257
+ shouldRenderAsSchematicBox: false
15258
+ };
15259
+ }
15260
+ initPorts() {
15261
+ const pinAliases = {
15262
+ pin1: ["collector", "c"],
15263
+ pin2: ["emitter", "e"],
15264
+ pin3: ["base", "b"]
15265
+ };
15266
+ super.initPorts({
15267
+ pinCount: 3,
15268
+ additionalAliases: pinAliases
15269
+ });
15270
+ }
15271
+ emitter = this.portMap.pin1;
15272
+ collector = this.portMap.pin2;
15273
+ base = this.portMap.pin3;
15274
+ doInitialCreateNetsFromProps() {
15275
+ this._createNetsFromProps([...this._getNetsFromConnectionsProp()]);
15276
+ }
15277
+ doInitialCreateTracesFromProps() {
15278
+ this._createTracesFromConnectionsProp();
15279
+ }
15280
+ doInitialSourceRender() {
15281
+ const { db } = this.root;
15282
+ const { _parsedProps: props } = this;
15283
+ const source_component = db.source_component.insert({
15284
+ ftype: "simple_transistor",
15285
+ name: this.name,
15286
+ transistor_type: props.type
15287
+ });
15288
+ this.source_component_id = source_component.source_component_id;
15289
+ }
15290
+ };
15291
+
15292
+ // lib/components/primitive-components/Group/Subcircuit/inflators/inflateSourceTransistor.ts
15293
+ function inflateSourceTransistor(sourceElm, inflatorContext) {
15294
+ const { injectionDb, subcircuit, groupsMap } = inflatorContext;
15295
+ const pcbElm = injectionDb.pcb_component.getWhere({
15296
+ source_component_id: sourceElm.source_component_id
15297
+ });
15298
+ const cadElm = injectionDb.cad_component.getWhere({
15299
+ source_component_id: sourceElm.source_component_id
15300
+ });
15301
+ const transistor = new Transistor({
15302
+ name: sourceElm.name,
15303
+ type: sourceElm.transistor_type,
15304
+ layer: pcbElm?.layer,
15305
+ pcbX: pcbElm?.center?.x,
15306
+ pcbY: pcbElm?.center?.y,
15307
+ pcbRotation: pcbElm?.rotation,
15308
+ doNotPlace: pcbElm?.do_not_place,
15309
+ obstructsWithinBounds: pcbElm?.obstructs_within_bounds
15310
+ });
15311
+ if (pcbElm) {
15312
+ inflatePcbComponent(pcbElm, {
15313
+ ...inflatorContext,
15314
+ normalComponent: transistor
15315
+ });
15316
+ }
15317
+ if (sourceElm.source_group_id && groupsMap?.has(sourceElm.source_group_id)) {
15318
+ const group = groupsMap.get(sourceElm.source_group_id);
15319
+ group.add(transistor);
15320
+ } else {
15321
+ subcircuit.add(transistor);
15322
+ }
15323
+ }
15324
+
15325
+ // lib/utils/circuit-json/inflate-circuit-json.ts
15326
+ var inflateCircuitJson = (target, circuitJson, children) => {
15327
+ if (!circuitJson) return;
15328
+ const injectionDb = cju(circuitJson);
15329
+ if (circuitJson && children?.length > 0) {
15330
+ throw new Error("Component cannot have both circuitJson and children");
15331
+ }
15332
+ const groupsMap = /* @__PURE__ */ new Map();
15333
+ const inflationCtx = {
15334
+ injectionDb,
15335
+ subcircuit: target,
15336
+ groupsMap
15337
+ };
15338
+ const sourceGroups = injectionDb.source_group.list();
15339
+ for (const sourceGroup of sourceGroups) {
15340
+ inflateSourceGroup(sourceGroup, inflationCtx);
15341
+ }
15342
+ const sourceComponents = injectionDb.source_component.list();
15343
+ for (const sourceComponent of sourceComponents) {
15344
+ switch (sourceComponent.ftype) {
15345
+ case "simple_resistor":
15346
+ inflateSourceResistor(sourceComponent, inflationCtx);
15347
+ break;
15348
+ case "simple_capacitor":
15349
+ inflateSourceCapacitor(sourceComponent, inflationCtx);
15350
+ break;
15351
+ case "simple_inductor":
15352
+ inflateSourceInductor(sourceComponent, inflationCtx);
15353
+ break;
15354
+ case "simple_diode":
15355
+ inflateSourceDiode(sourceComponent, inflationCtx);
15356
+ break;
15357
+ case "simple_chip":
15358
+ inflateSourceChip(sourceComponent, inflationCtx);
15359
+ break;
15360
+ case "simple_transistor":
15361
+ inflateSourceTransistor(sourceComponent, inflationCtx);
15362
+ break;
15363
+ default:
15364
+ throw new Error(
15365
+ `No inflator implemented for source component ftype: "${sourceComponent.ftype}"`
15366
+ );
15367
+ }
15368
+ }
15369
+ const sourcePorts = injectionDb.source_port.list();
15370
+ for (const sourcePort of sourcePorts) {
15371
+ inflateSourcePort(sourcePort, inflationCtx);
15372
+ }
15373
+ const sourceTraces = injectionDb.source_trace.list();
15374
+ for (const sourceTrace of sourceTraces) {
15375
+ inflateSourceTrace(sourceTrace, inflationCtx);
15376
+ }
15377
+ };
15378
+
15379
+ // lib/components/normal-components/Board.ts
15380
+ import {
15381
+ checkEachPcbPortConnectedToPcbTraces,
15382
+ checkEachPcbTraceNonOverlapping,
15383
+ checkPcbComponentsOutOfBoard,
15384
+ checkPcbTracesOutOfBoard,
15385
+ checkDifferentNetViaSpacing,
15386
+ checkSameNetViaSpacing,
15387
+ checkPcbComponentOverlap,
15388
+ checkPinMustBeConnected
15389
+ } from "@tscircuit/checks";
15390
+ import { getBoundsFromPoints as getBoundsFromPoints4 } from "@tscircuit/math-utils";
15391
+ var MIN_EFFECTIVE_BORDER_RADIUS_MM = 0.01;
15392
+ var getRoundedRectOutline = (width, height, radius) => {
15393
+ const w2 = width / 2;
15394
+ const h2 = height / 2;
15395
+ const r = Math.min(radius, w2, h2);
15396
+ if (r < MIN_EFFECTIVE_BORDER_RADIUS_MM) {
15397
+ return [
15398
+ { x: -w2, y: -h2 },
15399
+ { x: w2, y: -h2 },
15400
+ { x: w2, y: h2 },
15401
+ { x: -w2, y: h2 }
15402
+ ];
15403
+ }
15404
+ const maxArcLengthPerSegment = 0.1;
15405
+ const segments = Math.max(
15406
+ 1,
15407
+ Math.ceil(Math.PI / 2 * r / maxArcLengthPerSegment)
15408
+ );
15409
+ const step = Math.PI / 2 / segments;
15410
+ const outline = [];
15411
+ outline.push({ x: -w2 + r, y: -h2 });
15412
+ outline.push({ x: w2 - r, y: -h2 });
15413
+ for (let i = 1; i <= segments; i++) {
15414
+ const theta = -Math.PI / 2 + i * step;
15415
+ outline.push({
15416
+ x: w2 - r + r * Math.cos(theta),
15417
+ y: -h2 + r + r * Math.sin(theta)
15418
+ });
15419
+ }
15420
+ outline.push({ x: w2, y: h2 - r });
15421
+ for (let i = 1; i <= segments; i++) {
15422
+ const theta = 0 + i * step;
15423
+ outline.push({
15424
+ x: w2 - r + r * Math.cos(theta),
15425
+ y: h2 - r + r * Math.sin(theta)
15426
+ });
15427
+ }
15428
+ outline.push({ x: -w2 + r, y: h2 });
15429
+ for (let i = 1; i <= segments; i++) {
15430
+ const theta = Math.PI / 2 + i * step;
15431
+ outline.push({
15432
+ x: -w2 + r + r * Math.cos(theta),
15433
+ y: h2 - r + r * Math.sin(theta)
15434
+ });
15435
+ }
15436
+ outline.push({ x: -w2, y: -h2 + r });
15437
+ for (let i = 1; i <= segments; i++) {
15438
+ const theta = Math.PI + i * step;
15439
+ outline.push({
15440
+ x: -w2 + r + r * Math.cos(theta),
15441
+ y: -h2 + r + r * Math.sin(theta)
15442
+ });
15443
+ }
15444
+ return outline;
15445
+ };
15446
+ var Board = class extends Group6 {
15447
+ pcb_board_id = null;
15448
+ source_board_id = null;
15449
+ _drcChecksComplete = false;
15450
+ _connectedSchematicPortPairs = /* @__PURE__ */ new Set();
15451
+ get isSubcircuit() {
15452
+ return true;
15453
+ }
15454
+ get isGroup() {
15455
+ return true;
15456
+ }
15457
+ get config() {
15458
+ return {
15459
+ componentName: "Board",
15460
+ zodProps: boardProps
15461
+ };
15462
+ }
15463
+ get boardThickness() {
15464
+ const { _parsedProps: props } = this;
15465
+ const pcbX = this._resolvePcbCoordinate(props.pcbX, "pcbX", {
15466
+ allowBoardVariables: false
15467
+ });
15468
+ const pcbY = this._resolvePcbCoordinate(props.pcbY, "pcbY", {
15469
+ allowBoardVariables: false
15470
+ });
15471
+ return props.thickness ?? 1.4;
15472
+ }
15473
+ /**
15474
+ * Get all available layers for the board
15475
+ */
15476
+ get allLayers() {
15477
+ const layerCount = this._parsedProps.layers ?? 2;
15478
+ if (layerCount === 4) {
15479
+ return ["top", "bottom", "inner1", "inner2"];
15480
+ }
15481
+ return ["top", "bottom"];
15482
+ }
15483
+ _getSubcircuitLayerCount() {
15484
+ return this._parsedProps.layers ?? 2;
15485
+ }
15486
+ _getBoardCalcVariables() {
15487
+ const { _parsedProps: props } = this;
15488
+ const isAutoSized = (props.width == null || props.height == null) && !props.outline;
15489
+ if (isAutoSized) return {};
15490
+ const dbBoard = this.pcb_board_id ? this.root?.db.pcb_board.get(this.pcb_board_id) : null;
15491
+ let width = dbBoard?.width ?? props.width;
15492
+ let height = dbBoard?.height ?? props.height;
15493
+ if ((width == null || height == null) && props.outline?.length) {
15494
+ const outlineBounds = getBoundsFromPoints4(props.outline);
15495
+ if (outlineBounds) {
15496
+ width ??= outlineBounds.maxX - outlineBounds.minX;
15497
+ height ??= outlineBounds.maxY - outlineBounds.minY;
15498
+ }
15499
+ }
15500
+ const { pcbX, pcbY } = this.getResolvedPcbPositionProp();
15501
+ const center = dbBoard?.center ?? {
15502
+ x: pcbX + (props.outlineOffsetX ?? 0),
15503
+ y: pcbY + (props.outlineOffsetY ?? 0)
15504
+ };
15505
+ const resolvedWidth = width ?? 0;
15506
+ const resolvedHeight = height ?? 0;
15507
+ return {
15508
+ "board.minx": center.x - resolvedWidth / 2,
15509
+ "board.maxx": center.x + resolvedWidth / 2,
15510
+ "board.miny": center.y - resolvedHeight / 2,
15511
+ "board.maxy": center.y + resolvedHeight / 2
15512
+ };
15513
+ }
15514
+ doInitialPcbBoardAutoSize() {
15515
+ if (this.root?.pcbDisabled) return;
15516
+ if (!this.pcb_board_id) return;
15517
+ const { db } = this.root;
15518
+ const { _parsedProps: props } = this;
15519
+ const pcbX = this._resolvePcbCoordinate(props.pcbX, "pcbX", {
15520
+ allowBoardVariables: false
15521
+ });
15522
+ const pcbY = this._resolvePcbCoordinate(props.pcbY, "pcbY", {
15523
+ allowBoardVariables: false
15524
+ });
15525
+ if (props.width && props.height || props.outline) return;
15526
+ let minX = Infinity;
15527
+ let minY = Infinity;
15528
+ let maxX = -Infinity;
15529
+ let maxY = -Infinity;
15530
+ const descendantIds = getDescendantSubcircuitIds(db, this.subcircuit_id);
15531
+ const allowedSubcircuitIds = /* @__PURE__ */ new Set([this.subcircuit_id, ...descendantIds]);
15532
+ const allPcbComponents = db.pcb_component.list().filter(
15533
+ (c) => c.subcircuit_id && allowedSubcircuitIds.has(c.subcircuit_id)
15534
+ );
15535
+ const allPcbGroups = db.pcb_group.list().filter(
15536
+ (g) => g.subcircuit_id && allowedSubcircuitIds.has(g.subcircuit_id)
15537
+ );
15538
+ let hasComponents = false;
15539
+ const updateBounds = (center2, width, height) => {
15540
+ if (width === 0 || height === 0) return;
15541
+ hasComponents = true;
15542
+ minX = Math.min(minX, center2.x - width / 2);
15543
+ minY = Math.min(minY, center2.y - height / 2);
15544
+ maxX = Math.max(maxX, center2.x + width / 2);
15545
+ maxY = Math.max(maxY, center2.y + height / 2);
15546
+ };
15547
+ for (const pcbComponent of allPcbComponents) {
15548
+ updateBounds(pcbComponent.center, pcbComponent.width, pcbComponent.height);
15549
+ }
15550
+ for (const pcbGroup of allPcbGroups) {
15551
+ let width = pcbGroup.width ?? 0;
15552
+ let height = pcbGroup.height ?? 0;
15553
+ if (pcbGroup.outline && pcbGroup.outline.length > 0) {
15554
+ const bounds = getBoundsFromPoints4(pcbGroup.outline);
15555
+ if (bounds) {
15556
+ width = bounds.maxX - bounds.minX;
15557
+ height = bounds.maxY - bounds.minY;
15558
+ }
15559
+ }
15560
+ updateBounds(pcbGroup.center, width, height);
15561
+ }
15562
+ if (props.boardAnchorPosition) {
15563
+ const { x, y } = props.boardAnchorPosition;
15564
+ minX = Math.min(minX, x);
15565
+ minY = Math.min(minY, y);
15566
+ maxX = Math.max(maxX, x);
15567
+ maxY = Math.max(maxY, y);
15568
+ }
15569
+ const padding = 2;
15570
+ const computedWidth = hasComponents ? maxX - minX + padding * 2 : 0;
15571
+ const computedHeight = hasComponents ? maxY - minY + padding * 2 : 0;
15572
+ const center = {
15573
+ x: hasComponents ? (minX + maxX) / 2 + (props.outlineOffsetX ?? 0) : (props.outlineOffsetX ?? 0) + pcbX,
15574
+ y: hasComponents ? (minY + maxY) / 2 + (props.outlineOffsetY ?? 0) : (props.outlineOffsetY ?? 0) + pcbY
15575
+ };
15576
+ const finalWidth = props.width ?? computedWidth;
15577
+ const finalHeight = props.height ?? computedHeight;
15578
+ let outline = props.outline;
15579
+ if (!outline && props.borderRadius != null && finalWidth > 0 && finalHeight > 0) {
15580
+ outline = getRoundedRectOutline(
15581
+ finalWidth,
15582
+ finalHeight,
15583
+ props.borderRadius
15584
+ );
15585
+ }
15586
+ const update = {
15587
+ width: finalWidth,
15588
+ height: finalHeight,
15589
+ center
15590
+ };
15591
+ if (outline) {
15592
+ update.outline = outline.map((point) => ({
15593
+ x: point.x + (props.outlineOffsetX ?? 0),
15594
+ y: point.y + (props.outlineOffsetY ?? 0)
15595
+ }));
15596
+ }
15597
+ db.pcb_board.update(this.pcb_board_id, update);
15598
+ }
15599
+ // Recompute autosize after child components update (e.g., async footprints)
15600
+ updatePcbBoardAutoSize() {
15601
+ this.doInitialPcbBoardAutoSize();
15602
+ }
15603
+ /**
15604
+ * Update the board information silkscreen text if platform config is set and
15605
+ * the project name, version, or url is set.
15606
+ */
15607
+ _addBoardInformationToSilkscreen() {
15608
+ const platform = this.root?.platform;
15609
+ if (!platform?.printBoardInformationToSilkscreen) return;
15610
+ const pcbBoard = this.root.db.pcb_board.get(this.pcb_board_id);
15611
+ if (!pcbBoard) return;
15612
+ const boardInformation = [];
15613
+ if (platform.projectName) boardInformation.push(platform.projectName);
15614
+ if (platform.version) boardInformation.push(`v${platform.version}`);
15615
+ if (platform.url) boardInformation.push(platform.url);
15616
+ if (boardInformation.length === 0) return;
15617
+ const text = boardInformation.join("\n");
15618
+ const marginX = 0.25;
15619
+ const marginY = 1;
15620
+ const position = {
15621
+ x: pcbBoard.center.x + pcbBoard.width / 2 - marginX,
15622
+ y: pcbBoard.center.y - pcbBoard.height / 2 + marginY
15623
+ };
15624
+ this.root.db.pcb_silkscreen_text.insert({
15625
+ pcb_component_id: this.pcb_board_id,
15626
+ layer: "top",
15627
+ font: "tscircuit2024",
15628
+ font_size: 0.45,
15629
+ text,
15630
+ ccw_rotation: 0,
15631
+ anchor_alignment: "bottom_right",
15632
+ anchor_position: position
15633
+ });
15634
+ }
15635
+ doInitialSourceRender() {
15636
+ super.doInitialSourceRender();
15637
+ const { db } = this.root;
15638
+ const source_board = db.source_board.insert({
15639
+ source_group_id: this.source_group_id,
15640
+ title: this.props.title || this.props.name
15641
+ });
15642
+ this.source_board_id = source_board.source_board_id;
15643
+ }
15644
+ doInitialInflateSubcircuitCircuitJson() {
15645
+ const { circuitJson, children } = this._parsedProps;
15646
+ inflateCircuitJson(this, circuitJson, children);
15647
+ }
15648
+ doInitialPcbComponentRender() {
15649
+ if (this.root?.pcbDisabled) return;
15650
+ const { db } = this.root;
15651
+ const { _parsedProps: props } = this;
15652
+ let computedWidth = props.width ?? 0;
15653
+ let computedHeight = props.height ?? 0;
15654
+ const { pcbX, pcbY } = this.getResolvedPcbPositionProp();
15655
+ let center = {
15656
+ x: pcbX + (props.outlineOffsetX ?? 0),
15657
+ y: pcbY + (props.outlineOffsetY ?? 0)
15658
+ };
15659
+ const { boardAnchorPosition, boardAnchorAlignment } = props;
15660
+ if (boardAnchorPosition) {
15661
+ center = getBoardCenterFromAnchor({
15662
+ boardAnchorPosition,
15663
+ boardAnchorAlignment: boardAnchorAlignment ?? "center",
15664
+ width: computedWidth,
15665
+ height: computedHeight
15666
+ });
15667
+ }
15668
+ if (props.outline) {
15669
+ const xValues = props.outline.map((point) => point.x);
15670
+ const yValues = props.outline.map((point) => point.y);
15671
+ const minX = Math.min(...xValues);
15672
+ const maxX = Math.max(...xValues);
15673
+ const minY = Math.min(...yValues);
15674
+ const maxY = Math.max(...yValues);
15675
+ computedWidth = maxX - minX;
15676
+ computedHeight = maxY - minY;
15677
+ center = {
15678
+ x: (minX + maxX) / 2 + (props.outlineOffsetX ?? 0),
15679
+ y: (minY + maxY) / 2 + (props.outlineOffsetY ?? 0)
15680
+ };
15681
+ }
15682
+ let outline = props.outline;
15683
+ if (!outline && props.borderRadius != null && computedWidth > 0 && computedHeight > 0) {
15684
+ outline = getRoundedRectOutline(
15685
+ computedWidth,
15686
+ computedHeight,
15687
+ props.borderRadius
15688
+ );
15689
+ }
15690
+ const pcb_board = db.pcb_board.insert({
15691
+ center,
15692
+ thickness: this.boardThickness,
15693
+ num_layers: this.allLayers.length,
15694
+ width: computedWidth,
15695
+ height: computedHeight,
15696
+ outline: outline?.map((point) => ({
15697
+ x: point.x + (props.outlineOffsetX ?? 0),
15698
+ y: point.y + (props.outlineOffsetY ?? 0)
15699
+ })),
15700
+ material: props.material
15701
+ });
15702
+ this.pcb_board_id = pcb_board.pcb_board_id;
15703
+ this._addBoardInformationToSilkscreen();
14811
15704
  }
14812
15705
  removePcbComponentRender() {
14813
15706
  const { db } = this.root;
@@ -15026,529 +15919,274 @@ function generateMouseBitesForEdge({
15026
15919
  mouseBitePosition = boardBottom;
15027
15920
  } else if (edge === "right") {
15028
15921
  mouseBitePosition = boardRight;
15029
- } else {
15030
- mouseBitePosition = boardLeft;
15031
- }
15032
- const sortedTabs = [...edgeTabs].sort((a, b) => {
15033
- if (isHorizontal) {
15034
- return a.center.x - b.center.x;
15035
- } else {
15036
- return a.center.y - b.center.y;
15037
- }
15038
- });
15039
- for (let i = 0; i < sortedTabs.length - 1; i++) {
15040
- const tab1 = sortedTabs[i];
15041
- const tab2 = sortedTabs[i + 1];
15042
- let gapStart;
15043
- let gapEnd;
15044
- if (isHorizontal) {
15045
- gapStart = tab1.center.x + tab1.width / 2;
15046
- gapEnd = tab2.center.x - tab2.width / 2;
15047
- } else {
15048
- gapStart = tab1.center.y + tab1.height / 2;
15049
- gapEnd = tab2.center.y - tab2.height / 2;
15050
- }
15051
- const gapLength = gapEnd - gapStart;
15052
- const totalMouseBiteWidth = mouseBitesPerGap * mouseBiteDiameter;
15053
- const totalSpacing = (mouseBitesPerGap - 1) * mouseBiteSpacing;
15054
- if (gapLength < totalMouseBiteWidth + totalSpacing) continue;
15055
- const gapCenter = (gapStart + gapEnd) / 2;
15056
- for (let j = 0; j < mouseBitesPerGap; j++) {
15057
- const posOffset = (j - (mouseBitesPerGap - 1) / 2) * (mouseBiteDiameter + mouseBiteSpacing);
15058
- const newMouseBite = isHorizontal ? { x: gapCenter + posOffset, y: mouseBitePosition } : { x: mouseBitePosition, y: gapCenter + posOffset };
15059
- const radius2 = mouseBiteDiameter / 2;
15060
- let overlapsBoard = false;
15061
- for (const otherBoard of allBoards) {
15062
- if (!otherBoard.width || !otherBoard.height) continue;
15063
- const boardRect = {
15064
- center: otherBoard.center,
15065
- width: otherBoard.width,
15066
- height: otherBoard.height
15067
- };
15068
- if (pointOverlapsRectangle(newMouseBite, radius2, boardRect)) {
15069
- overlapsBoard = true;
15070
- break;
15071
- }
15072
- }
15073
- if (overlapsBoard) continue;
15074
- mouseBites.push(newMouseBite);
15075
- }
15076
- }
15077
- return mouseBites;
15078
- }
15079
- function generatePanelTabsAndMouseBites(boards, options) {
15080
- const allTabCutouts = [];
15081
- const allMouseBites = [];
15082
- for (let boardIndex = 0; boardIndex < boards.length; boardIndex++) {
15083
- const board = boards[boardIndex];
15084
- const otherBoards = boards.filter((_, i) => i !== boardIndex);
15085
- for (const edge of ["top", "bottom", "left", "right"]) {
15086
- const edgeTabs = generateTabsForEdge({
15087
- board,
15088
- edge,
15089
- otherBoards,
15090
- options
15091
- });
15092
- allTabCutouts.push(...edgeTabs);
15093
- if (options.mouseBites) {
15094
- const edgeMouseBites = generateMouseBitesForEdge({
15095
- board,
15096
- edge,
15097
- edgeTabs,
15098
- allBoards: otherBoards,
15099
- options
15100
- });
15101
- allMouseBites.push(...edgeMouseBites);
15102
- }
15103
- }
15104
- }
15105
- const tabCutouts = allTabCutouts.map((tab, index) => {
15106
- const tabWidthDimension = Math.min(tab.width, tab.height);
15107
- return {
15108
- type: "pcb_cutout",
15109
- pcb_cutout_id: `panel_tab_${index}`,
15110
- shape: "rect",
15111
- center: tab.center,
15112
- width: tab.width,
15113
- height: tab.height,
15114
- corner_radius: tabWidthDimension / 2
15115
- };
15116
- });
15117
- const mouseBiteDiameter = options.tabWidth * 0.45;
15118
- const mouseBiteHoles = allMouseBites.map((bite, index) => ({
15119
- type: "pcb_hole",
15120
- pcb_hole_id: `panel_mouse_bite_${index}`,
15121
- hole_shape: "circle",
15122
- hole_diameter: mouseBiteDiameter,
15123
- x: bite.x,
15124
- y: bite.y
15125
- }));
15126
- return {
15127
- tabCutouts,
15128
- mouseBiteHoles
15129
- };
15130
- }
15131
-
15132
- // lib/components/normal-components/Panel.ts
15133
- var Panel = class extends Group6 {
15134
- pcb_panel_id = null;
15135
- _tabsAndMouseBitesGenerated = false;
15136
- get config() {
15137
- return {
15138
- componentName: "Panel",
15139
- zodProps: panelProps
15140
- };
15141
- }
15142
- get isGroup() {
15143
- return true;
15144
- }
15145
- get isSubcircuit() {
15146
- return true;
15147
- }
15148
- add(component) {
15149
- if (component.lowercaseComponentName !== "board") {
15150
- throw new Error("<panel> can only contain <board> elements");
15151
- }
15152
- super.add(component);
15153
- }
15154
- doInitialPcbComponentAnchorAlignment() {
15155
- if (this.root?.pcbDisabled) return;
15156
- super.doInitialPcbComponentAnchorAlignment();
15157
- const { db } = this.root;
15158
- const childBoardInstances = this.children.filter(
15159
- (c) => c instanceof Board
15160
- );
15161
- const hasAnyPositionedBoards = childBoardInstances.some(
15162
- (b) => b.props.pcbX !== void 0 || b.props.pcbY !== void 0
15163
- );
15164
- const unpositionedBoards = childBoardInstances.filter(
15165
- (b) => b.props.pcbX === void 0 && b.props.pcbY === void 0
15166
- );
15167
- if (unpositionedBoards.length > 0 && !hasAnyPositionedBoards) {
15168
- const tabWidth = this._parsedProps.tabWidth ?? DEFAULT_TAB_WIDTH;
15169
- const boardGap = this._parsedProps.boardGap ?? tabWidth;
15170
- const gridCols = Math.ceil(Math.sqrt(unpositionedBoards.length));
15171
- const gridRows = Math.ceil(unpositionedBoards.length / gridCols);
15172
- const colWidths = Array(gridCols).fill(0);
15173
- const rowHeights = Array(gridRows).fill(0);
15174
- unpositionedBoards.forEach((board, i) => {
15175
- const col = i % gridCols;
15176
- const row = Math.floor(i / gridCols);
15177
- const pcbBoard = db.pcb_board.get(board.pcb_board_id);
15178
- if (!pcbBoard || pcbBoard.width === void 0 || pcbBoard.height === void 0)
15179
- return;
15180
- colWidths[col] = Math.max(colWidths[col], pcbBoard.width);
15181
- rowHeights[row] = Math.max(rowHeights[row], pcbBoard.height);
15182
- });
15183
- const totalGridWidth = colWidths.reduce((a, b) => a + b, 0) + (gridCols > 1 ? (gridCols - 1) * boardGap : 0);
15184
- const totalGridHeight = rowHeights.reduce((a, b) => a + b, 0) + (gridRows > 1 ? (gridRows - 1) * boardGap : 0);
15185
- const startX = -totalGridWidth / 2;
15186
- const startY = -totalGridHeight / 2;
15187
- const rowYOffsets = [startY];
15188
- for (let i = 0; i < gridRows - 1; i++) {
15189
- rowYOffsets.push(rowYOffsets[i] + rowHeights[i] + boardGap);
15190
- }
15191
- const colXOffsets = [startX];
15192
- for (let i = 0; i < gridCols - 1; i++) {
15193
- colXOffsets.push(colXOffsets[i] + colWidths[i] + boardGap);
15194
- }
15195
- unpositionedBoards.forEach((board, i) => {
15196
- const col = i % gridCols;
15197
- const row = Math.floor(i / gridCols);
15198
- const pcbBoard = db.pcb_board.get(board.pcb_board_id);
15199
- if (!pcbBoard || !pcbBoard.width || !pcbBoard.height) return;
15200
- const xPos = colXOffsets[col] + colWidths[col] / 2;
15201
- const yPos = rowYOffsets[row] + rowHeights[row] / 2;
15202
- board._repositionOnPcb({ x: xPos, y: yPos });
15203
- db.pcb_board.update(board.pcb_board_id, {
15204
- center: { x: xPos, y: yPos }
15205
- });
15206
- });
15207
- const allBoardPcbIds = childBoardInstances.map((b) => b.pcb_board_id).filter((id) => !!id);
15208
- const allBoardsInPanel = db.pcb_board.list().filter((b) => allBoardPcbIds.includes(b.pcb_board_id));
15209
- let minX = Infinity;
15210
- let minY = Infinity;
15211
- let maxX = -Infinity;
15212
- let maxY = -Infinity;
15213
- for (const board of allBoardsInPanel) {
15214
- if (board.width === void 0 || board.height === void 0 || !isFinite(board.width) || !isFinite(board.height))
15215
- continue;
15216
- const left = board.center.x - board.width / 2;
15217
- const right = board.center.x + board.width / 2;
15218
- const bottom = board.center.y - board.height / 2;
15219
- const top = board.center.y + board.height / 2;
15220
- minX = Math.min(minX, left);
15221
- maxX = Math.max(maxX, right);
15222
- minY = Math.min(minY, bottom);
15223
- maxY = Math.max(maxY, top);
15224
- }
15225
- if (isFinite(minX)) {
15226
- const boundsWidth = maxX - minX;
15227
- const boundsHeight = maxY - minY;
15228
- const newPanelWidth = boundsWidth + 2 * DEFAULT_PANEL_MARGIN;
15229
- const newPanelHeight = boundsHeight + 2 * DEFAULT_PANEL_MARGIN;
15230
- db.pcb_panel.update(this.pcb_panel_id, {
15231
- width: newPanelWidth,
15232
- height: newPanelHeight
15233
- });
15234
- }
15922
+ } else {
15923
+ mouseBitePosition = boardLeft;
15924
+ }
15925
+ const sortedTabs = [...edgeTabs].sort((a, b) => {
15926
+ if (isHorizontal) {
15927
+ return a.center.x - b.center.x;
15928
+ } else {
15929
+ return a.center.y - b.center.y;
15235
15930
  }
15236
- if (this._tabsAndMouseBitesGenerated) return;
15237
- const props = this._parsedProps;
15238
- const panelizationMethod = props.panelizationMethod ?? "tab-routing";
15239
- if (panelizationMethod !== "none") {
15240
- const childBoardIds = childBoardInstances.map((c) => c.pcb_board_id).filter((id) => !!id);
15241
- const boardsInPanel = db.pcb_board.list().filter((b) => childBoardIds.includes(b.pcb_board_id));
15242
- if (boardsInPanel.length === 0) return;
15243
- const tabWidth = props.tabWidth ?? DEFAULT_TAB_WIDTH;
15244
- const boardGap = props.boardGap ?? tabWidth;
15245
- const { tabCutouts, mouseBiteHoles } = generatePanelTabsAndMouseBites(
15246
- boardsInPanel,
15247
- {
15248
- boardGap,
15249
- tabWidth,
15250
- tabLength: props.tabLength ?? DEFAULT_TAB_LENGTH,
15251
- mouseBites: props.mouseBites ?? true
15931
+ });
15932
+ for (let i = 0; i < sortedTabs.length - 1; i++) {
15933
+ const tab1 = sortedTabs[i];
15934
+ const tab2 = sortedTabs[i + 1];
15935
+ let gapStart;
15936
+ let gapEnd;
15937
+ if (isHorizontal) {
15938
+ gapStart = tab1.center.x + tab1.width / 2;
15939
+ gapEnd = tab2.center.x - tab2.width / 2;
15940
+ } else {
15941
+ gapStart = tab1.center.y + tab1.height / 2;
15942
+ gapEnd = tab2.center.y - tab2.height / 2;
15943
+ }
15944
+ const gapLength = gapEnd - gapStart;
15945
+ const totalMouseBiteWidth = mouseBitesPerGap * mouseBiteDiameter;
15946
+ const totalSpacing = (mouseBitesPerGap - 1) * mouseBiteSpacing;
15947
+ if (gapLength < totalMouseBiteWidth + totalSpacing) continue;
15948
+ const gapCenter = (gapStart + gapEnd) / 2;
15949
+ for (let j = 0; j < mouseBitesPerGap; j++) {
15950
+ const posOffset = (j - (mouseBitesPerGap - 1) / 2) * (mouseBiteDiameter + mouseBiteSpacing);
15951
+ const newMouseBite = isHorizontal ? { x: gapCenter + posOffset, y: mouseBitePosition } : { x: mouseBitePosition, y: gapCenter + posOffset };
15952
+ const radius2 = mouseBiteDiameter / 2;
15953
+ let overlapsBoard = false;
15954
+ for (const otherBoard of allBoards) {
15955
+ if (!otherBoard.width || !otherBoard.height) continue;
15956
+ const boardRect = {
15957
+ center: otherBoard.center,
15958
+ width: otherBoard.width,
15959
+ height: otherBoard.height
15960
+ };
15961
+ if (pointOverlapsRectangle(newMouseBite, radius2, boardRect)) {
15962
+ overlapsBoard = true;
15963
+ break;
15252
15964
  }
15253
- );
15254
- for (const tabCutout of tabCutouts) {
15255
- db.pcb_cutout.insert(tabCutout);
15256
- }
15257
- for (const mouseBiteHole of mouseBiteHoles) {
15258
- db.pcb_hole.insert(mouseBiteHole);
15259
15965
  }
15966
+ if (overlapsBoard) continue;
15967
+ mouseBites.push(newMouseBite);
15260
15968
  }
15261
- this._tabsAndMouseBitesGenerated = true;
15262
15969
  }
15263
- runRenderCycle() {
15264
- if (!this.children.some((child) => child.componentName === "Board")) {
15265
- throw new Error("<panel> must contain at least one <board>");
15970
+ return mouseBites;
15971
+ }
15972
+ function generatePanelTabsAndMouseBites(boards, options) {
15973
+ const allTabCutouts = [];
15974
+ const allMouseBites = [];
15975
+ for (let boardIndex = 0; boardIndex < boards.length; boardIndex++) {
15976
+ const board = boards[boardIndex];
15977
+ const otherBoards = boards.filter((_, i) => i !== boardIndex);
15978
+ for (const edge of ["top", "bottom", "left", "right"]) {
15979
+ const edgeTabs = generateTabsForEdge({
15980
+ board,
15981
+ edge,
15982
+ otherBoards,
15983
+ options
15984
+ });
15985
+ allTabCutouts.push(...edgeTabs);
15986
+ if (options.mouseBites) {
15987
+ const edgeMouseBites = generateMouseBitesForEdge({
15988
+ board,
15989
+ edge,
15990
+ edgeTabs,
15991
+ allBoards: otherBoards,
15992
+ options
15993
+ });
15994
+ allMouseBites.push(...edgeMouseBites);
15995
+ }
15266
15996
  }
15267
- super.runRenderCycle();
15268
- }
15269
- doInitialPcbComponentRender() {
15270
- super.doInitialPcbComponentRender();
15271
- if (this.root?.pcbDisabled) return;
15272
- const { db } = this.root;
15273
- const props = this._parsedProps;
15274
- const inserted = db.pcb_panel.insert({
15275
- width: distance9.parse(props.width),
15276
- height: distance9.parse(props.height),
15277
- center: this._getGlobalPcbPositionBeforeLayout(),
15278
- covered_with_solder_mask: !(props.noSolderMask ?? false)
15279
- });
15280
- this.pcb_panel_id = inserted.pcb_panel_id;
15281
- }
15282
- updatePcbComponentRender() {
15283
- if (this.root?.pcbDisabled) return;
15284
- if (!this.pcb_panel_id) return;
15285
- const { db } = this.root;
15286
- const props = this._parsedProps;
15287
- db.pcb_panel.update(this.pcb_panel_id, {
15288
- width: distance9.parse(props.width),
15289
- height: distance9.parse(props.height),
15290
- center: this._getGlobalPcbPositionBeforeLayout(),
15291
- covered_with_solder_mask: !(props.noSolderMask ?? false)
15292
- });
15293
- }
15294
- removePcbComponentRender() {
15295
- if (!this.pcb_panel_id) return;
15296
- this.root?.db.pcb_panel.delete(this.pcb_panel_id);
15297
- this.pcb_panel_id = null;
15298
- }
15299
- };
15300
-
15301
- // lib/components/normal-components/Capacitor.ts
15302
- import { capacitorProps } from "@tscircuit/props";
15303
-
15304
- // lib/utils/constants.ts
15305
- var stringProxy = new Proxy(
15306
- {},
15307
- {
15308
- get: (target, prop) => prop
15309
15997
  }
15310
- );
15311
- var FTYPE = stringProxy;
15312
- var SCHEMATIC_COMPONENT_OUTLINE_COLOR = "rgba(132, 0, 0)";
15313
- var SCHEMATIC_COMPONENT_OUTLINE_STROKE_WIDTH = 0.12;
15314
-
15315
- // lib/components/normal-components/Capacitor.ts
15316
- import { formatSiUnit } from "format-si-unit";
15317
- var Capacitor = class extends NormalComponent3 {
15318
- _adjustSilkscreenTextAutomatically = true;
15319
- // @ts-ignore (cause the symbolName is string and not fixed)
15320
- get config() {
15998
+ const tabCutouts = allTabCutouts.map((tab, index) => {
15999
+ const tabWidthDimension = Math.min(tab.width, tab.height);
15321
16000
  return {
15322
- componentName: "Capacitor",
15323
- schematicSymbolName: this.props.polarized ? "capacitor_polarized" : this.props.symbolName ?? "capacitor",
15324
- zodProps: capacitorProps,
15325
- sourceFtype: FTYPE.simple_capacitor
16001
+ type: "pcb_cutout",
16002
+ pcb_cutout_id: `panel_tab_${index}`,
16003
+ shape: "rect",
16004
+ center: tab.center,
16005
+ width: tab.width,
16006
+ height: tab.height,
16007
+ corner_radius: tabWidthDimension / 2
15326
16008
  };
15327
- }
15328
- initPorts() {
15329
- if (typeof this.props.footprint === "string") {
15330
- super.initPorts({
15331
- additionalAliases: {
15332
- pin1: ["anode", "pos"],
15333
- pin2: ["cathode", "neg"]
15334
- }
15335
- });
15336
- } else {
15337
- super.initPorts();
15338
- }
15339
- }
15340
- _getSchematicSymbolDisplayValue() {
15341
- const inputCapacitance = this.props.capacitance;
15342
- const capacitanceDisplay = typeof inputCapacitance === "string" ? inputCapacitance : `${formatSiUnit(this._parsedProps.capacitance)}F`;
15343
- if (this._parsedProps.schShowRatings && this._parsedProps.maxVoltageRating) {
15344
- return `${capacitanceDisplay}/${formatSiUnit(this._parsedProps.maxVoltageRating)}V`;
15345
- }
15346
- return capacitanceDisplay;
15347
- }
15348
- doInitialCreateNetsFromProps() {
15349
- this._createNetsFromProps([
15350
- this.props.decouplingFor,
15351
- this.props.decouplingTo,
15352
- ...this._getNetsFromConnectionsProp()
15353
- ]);
15354
- }
15355
- doInitialCreateTracesFromProps() {
15356
- if (this.props.decouplingFor && this.props.decouplingTo) {
15357
- this.add(
15358
- new Trace3({
15359
- from: `${this.getSubcircuitSelector()} > port.1`,
15360
- to: this.props.decouplingFor
15361
- })
15362
- );
15363
- this.add(
15364
- new Trace3({
15365
- from: `${this.getSubcircuitSelector()} > port.2`,
15366
- to: this.props.decouplingTo
15367
- })
15368
- );
15369
- }
15370
- this._createTracesFromConnectionsProp();
15371
- }
15372
- doInitialSourceRender() {
15373
- const { db } = this.root;
15374
- const { _parsedProps: props } = this;
15375
- const source_component = db.source_component.insert({
15376
- ftype: "simple_capacitor",
15377
- name: this.name,
15378
- // @ts-ignore
15379
- manufacturer_part_number: props.manufacturerPartNumber ?? props.mfn,
15380
- supplier_part_numbers: props.supplierPartNumbers,
15381
- capacitance: props.capacitance,
15382
- max_voltage_rating: props.maxVoltageRating,
15383
- max_decoupling_trace_length: props.maxDecouplingTraceLength,
15384
- display_capacitance: this._getSchematicSymbolDisplayValue(),
15385
- are_pins_interchangeable: !props.polarized
15386
- });
15387
- this.source_component_id = source_component.source_component_id;
15388
- }
15389
- };
16009
+ });
16010
+ const mouseBiteDiameter = options.tabWidth * 0.45;
16011
+ const mouseBiteHoles = allMouseBites.map((bite, index) => ({
16012
+ type: "pcb_hole",
16013
+ pcb_hole_id: `panel_mouse_bite_${index}`,
16014
+ hole_shape: "circle",
16015
+ hole_diameter: mouseBiteDiameter,
16016
+ x: bite.x,
16017
+ y: bite.y
16018
+ }));
16019
+ return {
16020
+ tabCutouts,
16021
+ mouseBiteHoles
16022
+ };
16023
+ }
15390
16024
 
15391
- // lib/components/normal-components/Chip.ts
15392
- import { chipProps as chipProps2 } from "@tscircuit/props";
15393
- import { pcb_component_invalid_layer_error as pcb_component_invalid_layer_error2 } from "circuit-json";
15394
- var Chip = class extends NormalComponent3 {
15395
- schematicBoxDimensions = null;
15396
- constructor(props) {
15397
- super(props);
15398
- }
16025
+ // lib/components/normal-components/Panel.ts
16026
+ var Panel = class extends Group6 {
16027
+ pcb_panel_id = null;
16028
+ _tabsAndMouseBitesGenerated = false;
15399
16029
  get config() {
15400
16030
  return {
15401
- componentName: "Chip",
15402
- zodProps: chipProps2,
15403
- shouldRenderAsSchematicBox: true
16031
+ componentName: "Panel",
16032
+ zodProps: panelProps
15404
16033
  };
15405
16034
  }
15406
- initPorts(opts = {}) {
15407
- super.initPorts(opts);
15408
- const { _parsedProps: props } = this;
15409
- const { pcbX, pcbY } = this.getResolvedPcbPositionProp();
15410
- if (props.externallyConnectedPins) {
15411
- const requiredPorts = /* @__PURE__ */ new Set();
15412
- for (const [pin1, pin2] of props.externallyConnectedPins) {
15413
- requiredPorts.add(pin1);
15414
- requiredPorts.add(pin2);
15415
- }
15416
- for (const pinIdentifier of requiredPorts) {
15417
- const existingPort = this.children.find(
15418
- (child) => child instanceof Port && child.isMatchingAnyOf([pinIdentifier])
15419
- );
15420
- if (!existingPort) {
15421
- const pinMatch = pinIdentifier.match(/^pin(\d+)$/);
15422
- if (pinMatch) {
15423
- const pinNumber = parseInt(pinMatch[1]);
15424
- this.add(
15425
- new Port({
15426
- pinNumber,
15427
- aliases: [pinIdentifier]
15428
- })
15429
- );
15430
- } else {
15431
- this.add(
15432
- new Port({
15433
- name: pinIdentifier,
15434
- aliases: [pinIdentifier]
15435
- })
15436
- );
15437
- }
15438
- }
15439
- }
15440
- }
16035
+ get isGroup() {
16036
+ return true;
15441
16037
  }
15442
- doInitialSchematicComponentRender() {
15443
- const { _parsedProps: props } = this;
15444
- if (props?.noSchematicRepresentation === true) return;
15445
- super.doInitialSchematicComponentRender();
16038
+ get isSubcircuit() {
16039
+ return true;
15446
16040
  }
15447
- doInitialSourceRender() {
15448
- const { db } = this.root;
15449
- const { _parsedProps: props } = this;
15450
- const { pcbX, pcbY } = this.getResolvedPcbPositionProp();
15451
- const source_component = db.source_component.insert({
15452
- ftype: "simple_chip",
15453
- name: this.name,
15454
- manufacturer_part_number: props.manufacturerPartNumber,
15455
- supplier_part_numbers: props.supplierPartNumbers
15456
- });
15457
- this.source_component_id = source_component.source_component_id;
16041
+ add(component) {
16042
+ if (component.lowercaseComponentName !== "board") {
16043
+ throw new Error("<panel> can only contain <board> elements");
16044
+ }
16045
+ super.add(component);
15458
16046
  }
15459
- doInitialPcbComponentRender() {
16047
+ doInitialPanelLayout() {
15460
16048
  if (this.root?.pcbDisabled) return;
15461
16049
  const { db } = this.root;
15462
- const { _parsedProps: props } = this;
15463
- const { pcbX, pcbY } = this.getResolvedPcbPositionProp();
15464
- const componentLayer = props.layer ?? "top";
15465
- if (componentLayer !== "top" && componentLayer !== "bottom") {
15466
- const subcircuit = this.getSubcircuit();
15467
- const error = pcb_component_invalid_layer_error2.parse({
15468
- type: "pcb_component_invalid_layer_error",
15469
- message: `Component cannot be placed on layer '${componentLayer}'. Components can only be placed on 'top' or 'bottom' layers.`,
15470
- source_component_id: this.source_component_id,
15471
- layer: componentLayer,
15472
- subcircuit_id: subcircuit.subcircuit_id ?? void 0
16050
+ const childBoardInstances = this.children.filter(
16051
+ (c) => c instanceof Board
16052
+ );
16053
+ const hasAnyPositionedBoards = childBoardInstances.some(
16054
+ (b) => b.props.pcbX !== void 0 || b.props.pcbY !== void 0
16055
+ );
16056
+ const unpositionedBoards = childBoardInstances.filter(
16057
+ (b) => b.props.pcbX === void 0 && b.props.pcbY === void 0
16058
+ );
16059
+ if (unpositionedBoards.length > 0 && !hasAnyPositionedBoards) {
16060
+ const tabWidth = this._parsedProps.tabWidth ?? DEFAULT_TAB_WIDTH;
16061
+ const boardGap = this._parsedProps.boardGap ?? tabWidth;
16062
+ const gridCols = Math.ceil(Math.sqrt(unpositionedBoards.length));
16063
+ const gridRows = Math.ceil(unpositionedBoards.length / gridCols);
16064
+ const colWidths = Array(gridCols).fill(0);
16065
+ const rowHeights = Array(gridRows).fill(0);
16066
+ unpositionedBoards.forEach((board, i) => {
16067
+ const col = i % gridCols;
16068
+ const row = Math.floor(i / gridCols);
16069
+ const pcbBoard = db.pcb_board.get(board.pcb_board_id);
16070
+ if (!pcbBoard || pcbBoard.width === void 0 || pcbBoard.height === void 0)
16071
+ return;
16072
+ colWidths[col] = Math.max(colWidths[col], pcbBoard.width);
16073
+ rowHeights[row] = Math.max(rowHeights[row], pcbBoard.height);
15473
16074
  });
15474
- db.pcb_component_invalid_layer_error.insert(error);
15475
- }
15476
- const pcb_component = db.pcb_component.insert({
15477
- center: { x: pcbX, y: pcbY },
15478
- width: 2,
15479
- // Default width, adjust as needed
15480
- height: 3,
15481
- // Default height, adjust as needed
15482
- layer: componentLayer === "top" || componentLayer === "bottom" ? componentLayer : "top",
15483
- rotation: props.pcbRotation ?? 0,
15484
- source_component_id: this.source_component_id,
15485
- subcircuit_id: this.getSubcircuit().subcircuit_id ?? void 0,
15486
- do_not_place: props.doNotPlace ?? false,
15487
- obstructs_within_bounds: props.obstructsWithinBounds ?? true
15488
- });
15489
- this.pcb_component_id = pcb_component.pcb_component_id;
15490
- }
15491
- doInitialCreateTracesFromProps() {
15492
- const { _parsedProps: props } = this;
15493
- if (props.externallyConnectedPins) {
15494
- for (const [pin1, pin2] of props.externallyConnectedPins) {
15495
- this.add(
15496
- new Trace3({
15497
- from: `${this.getSubcircuitSelector()} > port.${pin1}`,
15498
- to: `${this.getSubcircuitSelector()} > port.${pin2}`
15499
- })
15500
- );
16075
+ const totalGridWidth = colWidths.reduce((a, b) => a + b, 0) + (gridCols > 1 ? (gridCols - 1) * boardGap : 0);
16076
+ const totalGridHeight = rowHeights.reduce((a, b) => a + b, 0) + (gridRows > 1 ? (gridRows - 1) * boardGap : 0);
16077
+ const startX = -totalGridWidth / 2;
16078
+ const startY = -totalGridHeight / 2;
16079
+ const rowYOffsets = [startY];
16080
+ for (let i = 0; i < gridRows - 1; i++) {
16081
+ rowYOffsets.push(rowYOffsets[i] + rowHeights[i] + boardGap);
16082
+ }
16083
+ const colXOffsets = [startX];
16084
+ for (let i = 0; i < gridCols - 1; i++) {
16085
+ colXOffsets.push(colXOffsets[i] + colWidths[i] + boardGap);
16086
+ }
16087
+ unpositionedBoards.forEach((board, i) => {
16088
+ const col = i % gridCols;
16089
+ const row = Math.floor(i / gridCols);
16090
+ const pcbBoard = db.pcb_board.get(board.pcb_board_id);
16091
+ if (!pcbBoard || !pcbBoard.width || !pcbBoard.height) return;
16092
+ const xPos = colXOffsets[col] + colWidths[col] / 2;
16093
+ const yPos = rowYOffsets[row] + rowHeights[row] / 2;
16094
+ board._repositionOnPcb({ x: xPos, y: yPos });
16095
+ db.pcb_board.update(board.pcb_board_id, {
16096
+ center: { x: xPos, y: yPos }
16097
+ });
16098
+ });
16099
+ const allBoardPcbIds = childBoardInstances.map((b) => b.pcb_board_id).filter((id) => !!id);
16100
+ const allBoardsInPanel = db.pcb_board.list().filter((b) => allBoardPcbIds.includes(b.pcb_board_id));
16101
+ let minX = Infinity;
16102
+ let minY = Infinity;
16103
+ let maxX = -Infinity;
16104
+ let maxY = -Infinity;
16105
+ for (const board of allBoardsInPanel) {
16106
+ if (board.width === void 0 || board.height === void 0 || !isFinite(board.width) || !isFinite(board.height))
16107
+ continue;
16108
+ const left = board.center.x - board.width / 2;
16109
+ const right = board.center.x + board.width / 2;
16110
+ const bottom = board.center.y - board.height / 2;
16111
+ const top = board.center.y + board.height / 2;
16112
+ minX = Math.min(minX, left);
16113
+ maxX = Math.max(maxX, right);
16114
+ minY = Math.min(minY, bottom);
16115
+ maxY = Math.max(maxY, top);
16116
+ }
16117
+ if (isFinite(minX)) {
16118
+ const boundsWidth = maxX - minX;
16119
+ const boundsHeight = maxY - minY;
16120
+ const newPanelWidth = boundsWidth + 2 * DEFAULT_PANEL_MARGIN;
16121
+ const newPanelHeight = boundsHeight + 2 * DEFAULT_PANEL_MARGIN;
16122
+ db.pcb_panel.update(this.pcb_panel_id, {
16123
+ width: newPanelWidth,
16124
+ height: newPanelHeight
16125
+ });
15501
16126
  }
15502
16127
  }
15503
- this._createTracesFromConnectionsProp();
15504
- }
15505
- doInitialSimulationRender() {
15506
- const { db } = this.root;
15507
- const { pinAttributes } = this.props;
15508
- if (!pinAttributes) return;
15509
- let powerPort = null;
15510
- let groundPort = null;
15511
- let voltage;
15512
- const ports = this.selectAll("port");
15513
- for (const port of ports) {
15514
- for (const alias of port.getNameAndAliases()) {
15515
- if (pinAttributes[alias]) {
15516
- const attributes = pinAttributes[alias];
15517
- if (attributes.providesPower) {
15518
- powerPort = port;
15519
- voltage = attributes.providesVoltage;
15520
- }
15521
- if (attributes.providesGround) {
15522
- groundPort = port;
15523
- }
16128
+ if (this._tabsAndMouseBitesGenerated) return;
16129
+ const props = this._parsedProps;
16130
+ const panelizationMethod = props.panelizationMethod ?? "tab-routing";
16131
+ if (panelizationMethod !== "none") {
16132
+ const childBoardIds = childBoardInstances.map((c) => c.pcb_board_id).filter((id) => !!id);
16133
+ const boardsInPanel = db.pcb_board.list().filter((b) => childBoardIds.includes(b.pcb_board_id));
16134
+ if (boardsInPanel.length === 0) return;
16135
+ const tabWidth = props.tabWidth ?? DEFAULT_TAB_WIDTH;
16136
+ const boardGap = props.boardGap ?? tabWidth;
16137
+ const { tabCutouts, mouseBiteHoles } = generatePanelTabsAndMouseBites(
16138
+ boardsInPanel,
16139
+ {
16140
+ boardGap,
16141
+ tabWidth,
16142
+ tabLength: props.tabLength ?? DEFAULT_TAB_LENGTH,
16143
+ mouseBites: props.mouseBites ?? true
15524
16144
  }
16145
+ );
16146
+ for (const tabCutout of tabCutouts) {
16147
+ db.pcb_cutout.insert(tabCutout);
16148
+ }
16149
+ for (const mouseBiteHole of mouseBiteHoles) {
16150
+ db.pcb_hole.insert(mouseBiteHole);
15525
16151
  }
15526
16152
  }
15527
- if (!powerPort || !groundPort || voltage === void 0) {
15528
- return;
15529
- }
15530
- const powerSourcePort = db.source_port.get(powerPort.source_port_id);
15531
- if (!powerSourcePort?.subcircuit_connectivity_map_key) return;
15532
- const groundSourcePort = db.source_port.get(groundPort.source_port_id);
15533
- if (!groundSourcePort?.subcircuit_connectivity_map_key) return;
15534
- const powerNet = db.source_net.getWhere({
15535
- subcircuit_connectivity_map_key: powerSourcePort.subcircuit_connectivity_map_key
15536
- });
15537
- const groundNet = db.source_net.getWhere({
15538
- subcircuit_connectivity_map_key: groundSourcePort.subcircuit_connectivity_map_key
15539
- });
15540
- if (!powerNet || !groundNet) {
15541
- return;
16153
+ this._tabsAndMouseBitesGenerated = true;
16154
+ }
16155
+ runRenderCycle() {
16156
+ if (!this.children.some((child) => child.componentName === "Board")) {
16157
+ throw new Error("<panel> must contain at least one <board>");
15542
16158
  }
15543
- ;
15544
- db.simulation_voltage_source.insert({
15545
- type: "simulation_voltage_source",
15546
- positive_source_port_id: powerPort.source_port_id,
15547
- positive_source_net_id: powerNet.source_net_id,
15548
- negative_source_port_id: groundPort.source_port_id,
15549
- negative_source_net_id: groundNet.source_net_id,
15550
- voltage
16159
+ super.runRenderCycle();
16160
+ }
16161
+ doInitialPcbComponentRender() {
16162
+ super.doInitialPcbComponentRender();
16163
+ if (this.root?.pcbDisabled) return;
16164
+ const { db } = this.root;
16165
+ const props = this._parsedProps;
16166
+ const inserted = db.pcb_panel.insert({
16167
+ width: distance9.parse(props.width),
16168
+ height: distance9.parse(props.height),
16169
+ center: this._getGlobalPcbPositionBeforeLayout(),
16170
+ covered_with_solder_mask: !(props.noSolderMask ?? false)
15551
16171
  });
16172
+ this.pcb_panel_id = inserted.pcb_panel_id;
16173
+ }
16174
+ updatePcbComponentRender() {
16175
+ if (this.root?.pcbDisabled) return;
16176
+ if (!this.pcb_panel_id) return;
16177
+ const { db } = this.root;
16178
+ const props = this._parsedProps;
16179
+ db.pcb_panel.update(this.pcb_panel_id, {
16180
+ width: distance9.parse(props.width),
16181
+ height: distance9.parse(props.height),
16182
+ center: this._getGlobalPcbPositionBeforeLayout(),
16183
+ covered_with_solder_mask: !(props.noSolderMask ?? false)
16184
+ });
16185
+ }
16186
+ removePcbComponentRender() {
16187
+ if (!this.pcb_panel_id) return;
16188
+ this.root?.db.pcb_panel.delete(this.pcb_panel_id);
16189
+ this.pcb_panel_id = null;
15552
16190
  }
15553
16191
  };
15554
16192
 
@@ -15578,55 +16216,9 @@ var Pinout = class extends Chip {
15578
16216
  }
15579
16217
  };
15580
16218
 
15581
- // lib/components/normal-components/Diode.ts
15582
- import { diodeProps } from "@tscircuit/props";
15583
- var Diode = class extends NormalComponent3 {
15584
- // @ts-ignore
15585
- get config() {
15586
- const symbolMap = {
15587
- schottky: "schottky_diode",
15588
- avalanche: "avalanche_diode",
15589
- zener: "zener_diode",
15590
- photodiode: "photodiode"
15591
- };
15592
- const variantSymbol = this.props.schottky ? "schottky" : this.props.avalanche ? "avalanche" : this.props.zener ? "zener" : this.props.photo ? "photodiode" : null;
15593
- return {
15594
- schematicSymbolName: variantSymbol ? symbolMap[variantSymbol] : this.props.symbolName ?? "diode",
15595
- componentName: "Diode",
15596
- zodProps: diodeProps,
15597
- sourceFtype: "simple_diode"
15598
- };
15599
- }
15600
- initPorts() {
15601
- super.initPorts({
15602
- additionalAliases: {
15603
- pin1: ["anode", "pos", "left"],
15604
- pin2: ["cathode", "neg", "right"]
15605
- }
15606
- });
15607
- }
15608
- doInitialSourceRender() {
15609
- const { db } = this.root;
15610
- const { _parsedProps: props } = this;
15611
- const source_component = db.source_component.insert({
15612
- ftype: "simple_diode",
15613
- name: this.name,
15614
- // @ts-ignore
15615
- manufacturer_part_number: props.manufacturerPartNumber ?? props.mfn,
15616
- supplier_part_numbers: props.supplierPartNumbers,
15617
- are_pins_interchangeable: false
15618
- });
15619
- this.source_component_id = source_component.source_component_id;
15620
- }
15621
- pos = this.portMap.pin1;
15622
- anode = this.portMap.pin1;
15623
- neg = this.portMap.pin2;
15624
- cathode = this.portMap.pin2;
15625
- };
15626
-
15627
16219
  // lib/components/normal-components/Fuse.ts
15628
16220
  import { fuseProps } from "@tscircuit/props";
15629
- import { formatSiUnit as formatSiUnit2 } from "format-si-unit";
16221
+ import { formatSiUnit as formatSiUnit4 } from "format-si-unit";
15630
16222
  var Fuse = class extends NormalComponent3 {
15631
16223
  get config() {
15632
16224
  return {
@@ -15641,7 +16233,7 @@ var Fuse = class extends NormalComponent3 {
15641
16233
  const rawVoltage = this._parsedProps.voltageRating;
15642
16234
  const current = typeof rawCurrent === "string" ? parseFloat(rawCurrent) : rawCurrent;
15643
16235
  const voltage = typeof rawVoltage === "string" ? parseFloat(rawVoltage) : rawVoltage;
15644
- return `${formatSiUnit2(current)}A / ${formatSiUnit2(voltage)}V`;
16236
+ return `${formatSiUnit4(current)}A / ${formatSiUnit4(voltage)}V`;
15645
16237
  }
15646
16238
  doInitialSourceRender() {
15647
16239
  const { db } = this.root;
@@ -15653,8 +16245,8 @@ var Fuse = class extends NormalComponent3 {
15653
16245
  ftype: FTYPE.simple_fuse,
15654
16246
  current_rating_amps: currentRating,
15655
16247
  voltage_rating_volts: voltageRating,
15656
- display_current_rating: `${formatSiUnit2(currentRating)}A`,
15657
- display_voltage_rating: `${formatSiUnit2(voltageRating)}V`
16248
+ display_current_rating: `${formatSiUnit4(currentRating)}A`,
16249
+ display_voltage_rating: `${formatSiUnit4(voltageRating)}V`
15658
16250
  });
15659
16251
  this.source_component_id = source_component.source_component_id;
15660
16252
  }
@@ -15763,944 +16355,583 @@ var Jumper = class extends NormalComponent3 {
15763
16355
  }
15764
16356
  };
15765
16357
 
15766
- // lib/components/normal-components/Interconnect.ts
15767
- import { interconnectProps } from "@tscircuit/props";
15768
- var INTERCONNECT_STANDARD_FOOTPRINTS = {
15769
- "0603": "0603",
15770
- "0805": "0805",
15771
- "1206": "1206"
15772
- };
15773
- var Interconnect = class extends NormalComponent3 {
15774
- get config() {
15775
- return {
15776
- componentName: "Interconnect",
15777
- zodProps: interconnectProps,
15778
- shouldRenderAsSchematicBox: true,
15779
- sourceFtype: "interconnect"
15780
- };
15781
- }
15782
- _getImpliedFootprintString() {
15783
- const { standard } = this._parsedProps;
15784
- if (!standard) return null;
15785
- return INTERCONNECT_STANDARD_FOOTPRINTS[standard] ?? null;
15786
- }
15787
- doInitialSourceRender() {
15788
- const { db } = this.root;
15789
- const source_component = db.source_component.insert({
15790
- ftype: "interconnect",
15791
- name: this.name,
15792
- are_pins_interchangeable: true
15793
- });
15794
- this.source_component_id = source_component.source_component_id;
15795
- }
15796
- };
15797
-
15798
- // lib/components/normal-components/SolderJumper.ts
15799
- import { solderjumperProps } from "@tscircuit/props";
15800
- var SolderJumper = class extends NormalComponent3 {
15801
- schematicDimensions = null;
15802
- _getPinNumberFromBridgedPinName(pinName) {
15803
- const port = this.selectOne(`port.${pinName}`, {
15804
- type: "port"
15805
- });
15806
- return port?._parsedProps.pinNumber ?? null;
15807
- }
15808
- get defaultInternallyConnectedPinNames() {
15809
- if (this._parsedProps.bridged) {
15810
- const pins = this.children.filter((c) => c.componentName === "Port").map((p) => p.name);
15811
- return pins.length > 0 ? [pins] : [];
15812
- }
15813
- return this._parsedProps.bridgedPins ?? [];
15814
- }
15815
- get config() {
15816
- const props = this._parsedProps ?? this.props;
15817
- let resolvedPinCount = props.pinCount;
15818
- if (props.pinCount == null && !props.footprint) {
15819
- resolvedPinCount = 2;
15820
- }
15821
- if (props.pinCount == null) {
15822
- const nums = (props.bridgedPins ?? []).flat().map((p_str) => this._getPinNumberFromBridgedPinName(p_str)).filter((n) => n !== null);
15823
- const maxPinFromBridged = nums.length > 0 ? Math.max(...nums) : 0;
15824
- const pinCountFromLabels = props.pinLabels ? Object.keys(props.pinLabels).length : 0;
15825
- const finalPinCount = Math.max(maxPinFromBridged, pinCountFromLabels);
15826
- if (finalPinCount === 2 || finalPinCount === 3) {
15827
- resolvedPinCount = finalPinCount;
15828
- }
15829
- if (resolvedPinCount == null && props.footprint && [2, 3].includes(this.getPortsFromFootprint().length)) {
15830
- resolvedPinCount = this.getPortsFromFootprint().length;
15831
- }
15832
- }
15833
- let symbolName = "";
15834
- if (resolvedPinCount) {
15835
- symbolName += `solderjumper${resolvedPinCount}`;
15836
- } else {
15837
- symbolName = "solderjumper";
15838
- }
15839
- let bridgedPinNumbers = [];
15840
- if (Array.isArray(props.bridgedPins) && props.bridgedPins.length > 0) {
15841
- bridgedPinNumbers = Array.from(
15842
- new Set(
15843
- props.bridgedPins.flat().map((pinName) => this._getPinNumberFromBridgedPinName(pinName)).filter((n) => n !== null)
15844
- )
15845
- ).sort((a, b) => a - b);
15846
- } else if (props.bridged && resolvedPinCount) {
15847
- bridgedPinNumbers = Array.from(
15848
- { length: resolvedPinCount },
15849
- (_, i) => i + 1
15850
- );
15851
- }
15852
- if (bridgedPinNumbers.length > 0) {
15853
- symbolName += `_bridged${bridgedPinNumbers.join("")}`;
15854
- }
15855
- return {
15856
- schematicSymbolName: props.symbolName ?? symbolName,
15857
- componentName: "SolderJumper",
15858
- zodProps: solderjumperProps,
15859
- shouldRenderAsSchematicBox: true
15860
- };
15861
- }
15862
- _getSchematicPortArrangement() {
15863
- const arrangement = super._getSchematicPortArrangement();
15864
- if (arrangement && Object.keys(arrangement).length > 0) return arrangement;
15865
- let pinCount = this._parsedProps.pinCount ?? (Array.isArray(this._parsedProps.pinLabels) ? this._parsedProps.pinLabels.length : this._parsedProps.pinLabels ? Object.keys(this._parsedProps.pinLabels).length : this.getPortsFromFootprint().length);
15866
- if (pinCount == null && !this._parsedProps.footprint) {
15867
- pinCount = 2;
15868
- }
15869
- const direction = this._parsedProps.schDirection ?? "right";
15870
- return {
15871
- leftSize: direction === "left" ? pinCount : 0,
15872
- rightSize: direction === "right" ? pinCount : 0
15873
- };
15874
- }
15875
- doInitialSourceRender() {
15876
- const { db } = this.root;
15877
- const { _parsedProps: props } = this;
15878
- const { pcbX, pcbY } = this.getResolvedPcbPositionProp();
15879
- const source_component = db.source_component.insert({
15880
- ftype: "simple_chip",
15881
- // TODO unknown or jumper
15882
- name: this.name,
15883
- manufacturer_part_number: props.manufacturerPartNumber,
15884
- supplier_part_numbers: props.supplierPartNumbers,
15885
- are_pins_interchangeable: true
15886
- });
15887
- this.source_component_id = source_component.source_component_id;
15888
- }
15889
- doInitialPcbComponentRender() {
15890
- if (this.root?.pcbDisabled) return;
15891
- const { db } = this.root;
15892
- const { _parsedProps: props } = this;
15893
- const { pcbX, pcbY } = this.getResolvedPcbPositionProp();
15894
- const pcb_component = db.pcb_component.insert({
15895
- center: { x: pcbX, y: pcbY },
15896
- width: 2,
15897
- // Default width, adjust as needed
15898
- height: 3,
15899
- // Default height, adjust as needed
15900
- layer: props.layer ?? "top",
15901
- rotation: props.pcbRotation ?? 0,
15902
- source_component_id: this.source_component_id,
15903
- subcircuit_id: this.getSubcircuit().subcircuit_id ?? void 0,
15904
- do_not_place: props.doNotPlace ?? false,
15905
- obstructs_within_bounds: props.obstructsWithinBounds ?? true
15906
- });
15907
- this.pcb_component_id = pcb_component.pcb_component_id;
15908
- }
15909
- doInitialPcbTraceRender() {
15910
- const { db } = this.root;
15911
- const pcb_ports = db.pcb_port.list({
15912
- pcb_component_id: this.pcb_component_id
15913
- });
15914
- const pinLabelToPortId = {};
15915
- for (let i = 0; i < pcb_ports.length; i++) {
15916
- const port = pcb_ports[i];
15917
- const sourcePort = db.source_port.get(port.source_port_id);
15918
- let pinLabel = "";
15919
- if (typeof sourcePort?.pin_number === "number") {
15920
- pinLabel = sourcePort.pin_number.toString();
15921
- } else if (Array.isArray(sourcePort?.port_hints)) {
15922
- let matchedHint = sourcePort.port_hints.find(
15923
- (h) => /^(pin)?\d+$/.test(h)
15924
- );
15925
- if (matchedHint) {
15926
- if (/^pin\d+$/.test(matchedHint)) {
15927
- pinLabel = matchedHint.replace(/^pin/, "");
15928
- } else {
15929
- pinLabel = matchedHint;
15930
- }
15931
- }
15932
- }
15933
- pinLabelToPortId[pinLabel] = port.pcb_port_id;
15934
- }
15935
- const traces = db.pcb_trace.list({
15936
- pcb_component_id: this.pcb_component_id
15937
- });
15938
- const updatePortId = (portId) => {
15939
- if (portId && typeof portId === "string" && portId.startsWith("{PIN")) {
15940
- const pin = portId.replace("{PIN", "").replace("}", "");
15941
- return pinLabelToPortId[pin] || portId;
15942
- }
15943
- return portId;
15944
- };
15945
- for (const trace of traces) {
15946
- if (!trace.route) continue;
15947
- for (const segment of trace.route) {
15948
- if (segment.route_type !== "wire") continue;
15949
- segment.start_pcb_port_id = updatePortId(segment.start_pcb_port_id);
15950
- segment.end_pcb_port_id = updatePortId(segment.end_pcb_port_id);
15951
- }
15952
- }
15953
- }
15954
- };
15955
-
15956
- // lib/components/normal-components/Led.ts
15957
- import { ledProps } from "@tscircuit/props";
15958
- var Led = class extends NormalComponent3 {
15959
- get config() {
15960
- const symbolMap = {
15961
- laser: "laser_diode"
15962
- };
15963
- const variantSymbol = this.props.laser ? "laser" : null;
15964
- return {
15965
- schematicSymbolName: variantSymbol ? symbolMap[variantSymbol] : this.props.symbolName ?? "led",
15966
- componentName: "Led",
15967
- zodProps: ledProps,
15968
- sourceFtype: "simple_led"
15969
- };
15970
- }
15971
- initPorts() {
15972
- super.initPorts({
15973
- additionalAliases: {
15974
- pin1: ["anode", "pos", "left"],
15975
- pin2: ["cathode", "neg", "right"]
15976
- }
15977
- });
15978
- }
15979
- _getSchematicSymbolDisplayValue() {
15980
- return this._parsedProps.schDisplayValue || this._parsedProps.color || void 0;
15981
- }
15982
- getFootprinterString() {
15983
- const baseFootprint = super.getFootprinterString();
15984
- if (baseFootprint && this.props.color) {
15985
- return `${baseFootprint}_color(${this.props.color})`;
15986
- }
15987
- return baseFootprint;
15988
- }
15989
- doInitialSourceRender() {
15990
- const { db } = this.root;
15991
- const { _parsedProps: props } = this;
15992
- const source_component = db.source_component.insert({
15993
- ftype: "simple_led",
15994
- name: this.name,
15995
- wave_length: props.wavelength,
15996
- color: props.color,
15997
- symbol_display_value: this._getSchematicSymbolDisplayValue(),
15998
- // @ts-ignore
15999
- manufacturer_part_number: props.manufacturerPartNumber ?? props.mfn,
16000
- supplier_part_numbers: props.supplierPartNumbers,
16001
- are_pins_interchangeable: false
16002
- });
16003
- this.source_component_id = source_component.source_component_id;
16004
- }
16005
- pos = this.portMap.pin1;
16006
- anode = this.portMap.pin1;
16007
- neg = this.portMap.pin2;
16008
- cathode = this.portMap.pin2;
16358
+ // lib/components/normal-components/Interconnect.ts
16359
+ import { interconnectProps } from "@tscircuit/props";
16360
+ var INTERCONNECT_STANDARD_FOOTPRINTS = {
16361
+ "0603": "0603",
16362
+ "0805": "0805",
16363
+ "1206": "1206"
16009
16364
  };
16010
-
16011
- // lib/components/normal-components/PowerSource.ts
16012
- import { powerSourceProps } from "@tscircuit/props";
16013
- var PowerSource = class extends NormalComponent3 {
16014
- // @ts-ignore
16365
+ var Interconnect = class extends NormalComponent3 {
16015
16366
  get config() {
16016
16367
  return {
16017
- // TBD in schematic_symbol and replace then
16018
- schematicSymbolName: this.props.symbolName ?? "power_factor_meter_horz",
16019
- componentName: "PowerSource",
16020
- zodProps: powerSourceProps,
16021
- sourceFtype: "simple_power_source"
16368
+ componentName: "Interconnect",
16369
+ zodProps: interconnectProps,
16370
+ shouldRenderAsSchematicBox: true,
16371
+ sourceFtype: "interconnect"
16022
16372
  };
16023
16373
  }
16024
- initPorts() {
16025
- this.add(
16026
- new Port({ name: "pin1", pinNumber: 1, aliases: ["positive", "pos"] })
16027
- );
16028
- this.add(
16029
- new Port({ name: "pin2", pinNumber: 2, aliases: ["negative", "neg"] })
16030
- );
16374
+ _getImpliedFootprintString() {
16375
+ const { standard } = this._parsedProps;
16376
+ if (!standard) return null;
16377
+ return INTERCONNECT_STANDARD_FOOTPRINTS[standard] ?? null;
16031
16378
  }
16032
16379
  doInitialSourceRender() {
16033
16380
  const { db } = this.root;
16034
- const { _parsedProps: props } = this;
16035
16381
  const source_component = db.source_component.insert({
16036
- ftype: "simple_power_source",
16382
+ ftype: "interconnect",
16037
16383
  name: this.name,
16038
- voltage: props.voltage,
16039
- supplier_part_numbers: props.supplierPartNumbers,
16040
- are_pins_interchangeable: false
16384
+ are_pins_interchangeable: true
16041
16385
  });
16042
16386
  this.source_component_id = source_component.source_component_id;
16043
16387
  }
16044
- pos = this.portMap.pin1;
16045
- positive = this.portMap.pin1;
16046
- neg = this.portMap.pin2;
16047
- negative = this.portMap.pin2;
16048
16388
  };
16049
16389
 
16050
- // lib/components/normal-components/VoltageSource.ts
16051
- import { voltageSourceProps } from "@tscircuit/props";
16052
- var VoltageSource = class extends NormalComponent3 {
16053
- get config() {
16054
- const isSquare = this.props.waveShape === "square";
16055
- return {
16056
- componentName: "VoltageSource",
16057
- schematicSymbolName: isSquare ? "square_wave" : "ac_voltmeter",
16058
- zodProps: voltageSourceProps,
16059
- sourceFtype: "simple_voltage_source"
16060
- };
16061
- }
16062
- runRenderPhaseForChildren(phase) {
16063
- if (phase.startsWith("Pcb")) {
16064
- return;
16065
- }
16066
- for (const child of this.children) {
16067
- child.runRenderPhaseForChildren(phase);
16068
- child.runRenderPhase(phase);
16069
- }
16070
- }
16071
- doInitialPcbComponentRender() {
16072
- }
16073
- initPorts() {
16074
- super.initPorts({
16075
- additionalAliases: {
16076
- pin1: ["terminal1"],
16077
- pin2: ["terminal2"]
16078
- }
16079
- });
16080
- }
16081
- doInitialSourceRender() {
16082
- const { db } = this.root;
16083
- const { _parsedProps: props } = this;
16084
- const source_component = db.source_component.insert({
16085
- ftype: "simple_voltage_source",
16086
- name: this.name,
16087
- voltage: props.voltage,
16088
- frequency: props.frequency,
16089
- peak_to_peak_voltage: props.peakToPeakVoltage,
16090
- wave_shape: props.waveShape,
16091
- phase: props.phase,
16092
- duty_cycle: props.dutyCycle,
16093
- supplier_part_numbers: props.supplierPartNumbers,
16094
- are_pins_interchangeable: true
16390
+ // lib/components/normal-components/SolderJumper.ts
16391
+ import { solderjumperProps } from "@tscircuit/props";
16392
+ var SolderJumper = class extends NormalComponent3 {
16393
+ schematicDimensions = null;
16394
+ _getPinNumberFromBridgedPinName(pinName) {
16395
+ const port = this.selectOne(`port.${pinName}`, {
16396
+ type: "port"
16095
16397
  });
16096
- this.source_component_id = source_component.source_component_id;
16398
+ return port?._parsedProps.pinNumber ?? null;
16097
16399
  }
16098
- doInitialSimulationRender() {
16099
- const { db } = this.root;
16100
- const { _parsedProps: props } = this;
16101
- const terminal1Port = this.portMap.terminal1;
16102
- const terminal2Port = this.portMap.terminal2;
16103
- db.simulation_voltage_source.insert({
16104
- type: "simulation_voltage_source",
16105
- is_dc_source: false,
16106
- terminal1_source_port_id: terminal1Port.source_port_id,
16107
- terminal2_source_port_id: terminal2Port.source_port_id,
16108
- voltage: props.voltage,
16109
- frequency: props.frequency,
16110
- peak_to_peak_voltage: props.peakToPeakVoltage,
16111
- wave_shape: props.waveShape,
16112
- phase: props.phase,
16113
- duty_cycle: props.dutyCycle
16114
- });
16400
+ get defaultInternallyConnectedPinNames() {
16401
+ if (this._parsedProps.bridged) {
16402
+ const pins = this.children.filter((c) => c.componentName === "Port").map((p) => p.name);
16403
+ return pins.length > 0 ? [pins] : [];
16404
+ }
16405
+ return this._parsedProps.bridgedPins ?? [];
16115
16406
  }
16116
- terminal1 = this.portMap.terminal1;
16117
- terminal2 = this.portMap.terminal2;
16118
- };
16119
-
16120
- // lib/components/normal-components/Resistor.ts
16121
- import { resistorProps } from "@tscircuit/props";
16122
- import { formatSiUnit as formatSiUnit3 } from "format-si-unit";
16123
- var Resistor = class extends NormalComponent3 {
16124
- _adjustSilkscreenTextAutomatically = true;
16125
16407
  get config() {
16126
- return {
16127
- componentName: "Resistor",
16128
- schematicSymbolName: this.props.symbolName ?? "boxresistor",
16129
- zodProps: resistorProps,
16130
- sourceFtype: "simple_resistor"
16131
- };
16132
- }
16133
- initPorts() {
16134
- super.initPorts({
16135
- additionalAliases: {
16136
- pin1: ["anode", "pos", "left"],
16137
- pin2: ["cathode", "neg", "right"]
16408
+ const props = this._parsedProps ?? this.props;
16409
+ let resolvedPinCount = props.pinCount;
16410
+ if (props.pinCount == null && !props.footprint) {
16411
+ resolvedPinCount = 2;
16412
+ }
16413
+ if (props.pinCount == null) {
16414
+ const nums = (props.bridgedPins ?? []).flat().map((p_str) => this._getPinNumberFromBridgedPinName(p_str)).filter((n) => n !== null);
16415
+ const maxPinFromBridged = nums.length > 0 ? Math.max(...nums) : 0;
16416
+ const pinCountFromLabels = props.pinLabels ? Object.keys(props.pinLabels).length : 0;
16417
+ const finalPinCount = Math.max(maxPinFromBridged, pinCountFromLabels);
16418
+ if (finalPinCount === 2 || finalPinCount === 3) {
16419
+ resolvedPinCount = finalPinCount;
16420
+ }
16421
+ if (resolvedPinCount == null && props.footprint && [2, 3].includes(this.getPortsFromFootprint().length)) {
16422
+ resolvedPinCount = this.getPortsFromFootprint().length;
16138
16423
  }
16139
- });
16140
- }
16141
- _getSchematicSymbolDisplayValue() {
16142
- return `${formatSiUnit3(this._parsedProps.resistance)}\u03A9`;
16143
- }
16144
- doInitialCreateNetsFromProps() {
16145
- this._createNetsFromProps([
16146
- this.props.pullupFor,
16147
- this.props.pullupTo,
16148
- this.props.pulldownFor,
16149
- this.props.pulldownTo,
16150
- ...this._getNetsFromConnectionsProp()
16151
- ]);
16152
- }
16153
- doInitialCreateTracesFromProps() {
16154
- if (this.props.pullupFor && this.props.pullupTo) {
16155
- this.add(
16156
- new Trace3({
16157
- from: `${this.getSubcircuitSelector()} > port.1`,
16158
- to: this.props.pullupFor
16159
- })
16160
- );
16161
- this.add(
16162
- new Trace3({
16163
- from: `${this.getSubcircuitSelector()} > port.2`,
16164
- to: this.props.pullupTo
16165
- })
16166
- );
16167
16424
  }
16168
- if (this.props.pulldownFor && this.props.pulldownTo) {
16169
- this.add(
16170
- new Trace3({
16171
- from: `${this.getSubcircuitSelector()} > port.1`,
16172
- to: this.props.pulldownFor
16173
- })
16174
- );
16175
- this.add(
16176
- new Trace3({
16177
- from: `${this.getSubcircuitSelector()} > port.2`,
16178
- to: this.props.pulldownTo
16179
- })
16425
+ let symbolName = "";
16426
+ if (resolvedPinCount) {
16427
+ symbolName += `solderjumper${resolvedPinCount}`;
16428
+ } else {
16429
+ symbolName = "solderjumper";
16430
+ }
16431
+ let bridgedPinNumbers = [];
16432
+ if (Array.isArray(props.bridgedPins) && props.bridgedPins.length > 0) {
16433
+ bridgedPinNumbers = Array.from(
16434
+ new Set(
16435
+ props.bridgedPins.flat().map((pinName) => this._getPinNumberFromBridgedPinName(pinName)).filter((n) => n !== null)
16436
+ )
16437
+ ).sort((a, b) => a - b);
16438
+ } else if (props.bridged && resolvedPinCount) {
16439
+ bridgedPinNumbers = Array.from(
16440
+ { length: resolvedPinCount },
16441
+ (_, i) => i + 1
16180
16442
  );
16181
16443
  }
16182
- this._createTracesFromConnectionsProp();
16444
+ if (bridgedPinNumbers.length > 0) {
16445
+ symbolName += `_bridged${bridgedPinNumbers.join("")}`;
16446
+ }
16447
+ return {
16448
+ schematicSymbolName: props.symbolName ?? symbolName,
16449
+ componentName: "SolderJumper",
16450
+ zodProps: solderjumperProps,
16451
+ shouldRenderAsSchematicBox: true
16452
+ };
16453
+ }
16454
+ _getSchematicPortArrangement() {
16455
+ const arrangement = super._getSchematicPortArrangement();
16456
+ if (arrangement && Object.keys(arrangement).length > 0) return arrangement;
16457
+ let pinCount = this._parsedProps.pinCount ?? (Array.isArray(this._parsedProps.pinLabels) ? this._parsedProps.pinLabels.length : this._parsedProps.pinLabels ? Object.keys(this._parsedProps.pinLabels).length : this.getPortsFromFootprint().length);
16458
+ if (pinCount == null && !this._parsedProps.footprint) {
16459
+ pinCount = 2;
16460
+ }
16461
+ const direction = this._parsedProps.schDirection ?? "right";
16462
+ return {
16463
+ leftSize: direction === "left" ? pinCount : 0,
16464
+ rightSize: direction === "right" ? pinCount : 0
16465
+ };
16183
16466
  }
16184
16467
  doInitialSourceRender() {
16185
16468
  const { db } = this.root;
16186
16469
  const { _parsedProps: props } = this;
16470
+ const { pcbX, pcbY } = this.getResolvedPcbPositionProp();
16187
16471
  const source_component = db.source_component.insert({
16188
- ftype: "simple_resistor",
16472
+ ftype: "simple_chip",
16473
+ // TODO unknown or jumper
16189
16474
  name: this.name,
16190
- // @ts-ignore
16191
- manufacturer_part_number: props.manufacturerPartNumber ?? props.mfn,
16475
+ manufacturer_part_number: props.manufacturerPartNumber,
16192
16476
  supplier_part_numbers: props.supplierPartNumbers,
16193
- resistance: props.resistance,
16194
- display_resistance: this._getSchematicSymbolDisplayValue(),
16195
16477
  are_pins_interchangeable: true
16196
16478
  });
16197
16479
  this.source_component_id = source_component.source_component_id;
16198
16480
  }
16199
- };
16200
-
16201
- // lib/components/primitive-components/Constraint.ts
16202
- import { constraintProps } from "@tscircuit/props";
16203
- import "zod";
16204
- var edgeSpecifiers = [
16205
- "leftedge",
16206
- "rightedge",
16207
- "topedge",
16208
- "bottomedge",
16209
- "center"
16210
- ];
16211
- var Constraint3 = class extends PrimitiveComponent2 {
16212
- get config() {
16213
- return {
16214
- componentName: "Constraint",
16215
- zodProps: constraintProps
16216
- };
16481
+ doInitialPcbComponentRender() {
16482
+ if (this.root?.pcbDisabled) return;
16483
+ const { db } = this.root;
16484
+ const { _parsedProps: props } = this;
16485
+ const { pcbX, pcbY } = this.getResolvedPcbPositionProp();
16486
+ const pcb_component = db.pcb_component.insert({
16487
+ center: { x: pcbX, y: pcbY },
16488
+ width: 2,
16489
+ // Default width, adjust as needed
16490
+ height: 3,
16491
+ // Default height, adjust as needed
16492
+ layer: props.layer ?? "top",
16493
+ rotation: props.pcbRotation ?? 0,
16494
+ source_component_id: this.source_component_id,
16495
+ subcircuit_id: this.getSubcircuit().subcircuit_id ?? void 0,
16496
+ do_not_place: props.doNotPlace ?? false,
16497
+ obstructs_within_bounds: props.obstructsWithinBounds ?? true
16498
+ });
16499
+ this.pcb_component_id = pcb_component.pcb_component_id;
16217
16500
  }
16218
- constructor(props) {
16219
- super(props);
16220
- if ("xdist" in props || "ydist" in props) {
16221
- if (!("edgeToEdge" in props) && !("centerToCenter" in props)) {
16222
- throw new Error(
16223
- `edgeToEdge, centerToCenter must be set for xDist or yDist for ${this}`
16501
+ doInitialPcbTraceRender() {
16502
+ const { db } = this.root;
16503
+ const pcb_ports = db.pcb_port.list({
16504
+ pcb_component_id: this.pcb_component_id
16505
+ });
16506
+ const pinLabelToPortId = {};
16507
+ for (let i = 0; i < pcb_ports.length; i++) {
16508
+ const port = pcb_ports[i];
16509
+ const sourcePort = db.source_port.get(port.source_port_id);
16510
+ let pinLabel = "";
16511
+ if (typeof sourcePort?.pin_number === "number") {
16512
+ pinLabel = sourcePort.pin_number.toString();
16513
+ } else if (Array.isArray(sourcePort?.port_hints)) {
16514
+ let matchedHint = sourcePort.port_hints.find(
16515
+ (h) => /^(pin)?\d+$/.test(h)
16224
16516
  );
16517
+ if (matchedHint) {
16518
+ if (/^pin\d+$/.test(matchedHint)) {
16519
+ pinLabel = matchedHint.replace(/^pin/, "");
16520
+ } else {
16521
+ pinLabel = matchedHint;
16522
+ }
16523
+ }
16225
16524
  }
16525
+ pinLabelToPortId[pinLabel] = port.pcb_port_id;
16226
16526
  }
16227
- if ("for" in props && props.for.length < 2) {
16228
- throw new Error(`"for" must have at least two selectors for ${this}`);
16229
- }
16230
- }
16231
- _getAllReferencedComponents() {
16232
- const componentsWithSelectors = [];
16233
- const container = this.getPrimitiveContainer();
16234
- function addComponentFromSelector(selector) {
16235
- const maybeEdge = selector.split(" ").pop();
16236
- const edge = edgeSpecifiers.includes(maybeEdge) ? maybeEdge : void 0;
16237
- const componentSelector = edge ? selector.replace(` ${edge}`, "") : selector;
16238
- const component = container.selectOne(componentSelector, {
16239
- pcbPrimitive: true
16240
- });
16241
- if (component) {
16242
- componentsWithSelectors.push({
16243
- selector,
16244
- component,
16245
- componentSelector,
16246
- edge
16247
- });
16248
- }
16249
- }
16250
- for (const key of ["left", "right", "top", "bottom"]) {
16251
- if (key in this._parsedProps) {
16252
- addComponentFromSelector(this._parsedProps[key]);
16527
+ const traces = db.pcb_trace.list({
16528
+ pcb_component_id: this.pcb_component_id
16529
+ });
16530
+ const updatePortId = (portId) => {
16531
+ if (portId && typeof portId === "string" && portId.startsWith("{PIN")) {
16532
+ const pin = portId.replace("{PIN", "").replace("}", "");
16533
+ return pinLabelToPortId[pin] || portId;
16253
16534
  }
16254
- }
16255
- if ("for" in this._parsedProps) {
16256
- for (const selector of this._parsedProps.for) {
16257
- addComponentFromSelector(selector);
16535
+ return portId;
16536
+ };
16537
+ for (const trace of traces) {
16538
+ if (!trace.route) continue;
16539
+ for (const segment of trace.route) {
16540
+ if (segment.route_type !== "wire") continue;
16541
+ segment.start_pcb_port_id = updatePortId(segment.start_pcb_port_id);
16542
+ segment.end_pcb_port_id = updatePortId(segment.end_pcb_port_id);
16258
16543
  }
16259
16544
  }
16260
- return { componentsWithSelectors };
16261
16545
  }
16262
16546
  };
16263
16547
 
16264
- // lib/components/primitive-components/FabricationNoteRect.ts
16265
- import { fabricationNoteRectProps } from "@tscircuit/props";
16266
- import "transformation-matrix";
16267
- var FabricationNoteRect = class extends PrimitiveComponent2 {
16268
- fabrication_note_rect_id = null;
16548
+ // lib/components/normal-components/Led.ts
16549
+ import { ledProps } from "@tscircuit/props";
16550
+ var Led = class extends NormalComponent3 {
16269
16551
  get config() {
16270
- return {
16271
- componentName: "FabricationNoteRect",
16272
- zodProps: fabricationNoteRectProps
16552
+ const symbolMap = {
16553
+ laser: "laser_diode"
16273
16554
  };
16274
- }
16275
- doInitialPcbPrimitiveRender() {
16276
- if (this.root?.pcbDisabled) return;
16277
- const { db } = this.root;
16278
- const { _parsedProps: props } = this;
16279
- const { pcbX, pcbY } = this.getResolvedPcbPositionProp();
16280
- const { maybeFlipLayer } = this._getPcbPrimitiveFlippedHelpers();
16281
- const layer = maybeFlipLayer(props.layer ?? "top");
16282
- if (layer !== "top" && layer !== "bottom") {
16283
- throw new Error(
16284
- `Invalid layer "${layer}" for FabricationNoteRect. Must be "top" or "bottom".`
16285
- );
16286
- }
16287
- const pcb_component_id = this.parent?.pcb_component_id ?? this.getPrimitiveContainer()?.pcb_component_id;
16288
- const subcircuit = this.getSubcircuit();
16289
- const hasStroke = props.hasStroke ?? (props.strokeWidth !== void 0 && props.strokeWidth !== null);
16290
- const fabrication_note_rect = db.pcb_fabrication_note_rect.insert({
16291
- pcb_component_id,
16292
- layer,
16293
- color: props.color,
16294
- center: {
16295
- x: pcbX,
16296
- y: pcbY
16297
- },
16298
- width: props.width,
16299
- height: props.height,
16300
- stroke_width: props.strokeWidth ?? 1,
16301
- is_filled: props.isFilled ?? false,
16302
- has_stroke: hasStroke,
16303
- is_stroke_dashed: props.isStrokeDashed ?? false,
16304
- subcircuit_id: subcircuit?.subcircuit_id ?? void 0,
16305
- pcb_group_id: this.getGroup()?.pcb_group_id ?? void 0,
16306
- corner_radius: props.cornerRadius ?? void 0
16307
- });
16308
- this.fabrication_note_rect_id = fabrication_note_rect.pcb_fabrication_note_rect_id;
16309
- }
16310
- getPcbSize() {
16311
- const { _parsedProps: props } = this;
16312
- return { width: props.width, height: props.height };
16313
- }
16314
- };
16315
-
16316
- // lib/components/primitive-components/FabricationNotePath.ts
16317
- import { fabricationNotePathProps } from "@tscircuit/props";
16318
- import { applyToPoint as applyToPoint10 } from "transformation-matrix";
16319
- var FabricationNotePath = class extends PrimitiveComponent2 {
16320
- fabrication_note_path_id = null;
16321
- get config() {
16555
+ const variantSymbol = this.props.laser ? "laser" : null;
16322
16556
  return {
16323
- componentName: "FabricationNotePath",
16324
- zodProps: fabricationNotePathProps
16557
+ schematicSymbolName: variantSymbol ? symbolMap[variantSymbol] : this.props.symbolName ?? "led",
16558
+ componentName: "Led",
16559
+ zodProps: ledProps,
16560
+ sourceFtype: "simple_led"
16325
16561
  };
16326
16562
  }
16327
- doInitialPcbPrimitiveRender() {
16328
- if (this.root?.pcbDisabled) return;
16329
- const { db } = this.root;
16330
- const subcircuit = this.getSubcircuit();
16331
- const { _parsedProps: props } = this;
16332
- const layer = props.layer ?? "top";
16333
- if (layer !== "top" && layer !== "bottom") {
16334
- throw new Error(
16335
- `Invalid layer "${layer}" for SilkscreenPath. Must be "top" or "bottom".`
16336
- );
16337
- }
16338
- const transform = this._computePcbGlobalTransformBeforeLayout();
16339
- const pcb_component_id = this.parent?.pcb_component_id ?? this.getPrimitiveContainer()?.pcb_component_id;
16340
- const fabrication_note_path = db.pcb_fabrication_note_path.insert({
16341
- pcb_component_id,
16342
- layer,
16343
- color: props.color,
16344
- route: props.route.map((p) => {
16345
- const transformedPosition = applyToPoint10(transform, {
16346
- x: p.x,
16347
- y: p.y
16348
- });
16349
- return {
16350
- ...p,
16351
- x: transformedPosition.x,
16352
- y: transformedPosition.y
16353
- };
16354
- }),
16355
- stroke_width: props.strokeWidth ?? 0.1,
16356
- subcircuit_id: subcircuit?.subcircuit_id ?? void 0
16563
+ initPorts() {
16564
+ super.initPorts({
16565
+ additionalAliases: {
16566
+ pin1: ["anode", "pos", "left"],
16567
+ pin2: ["cathode", "neg", "right"]
16568
+ }
16357
16569
  });
16358
- this.fabrication_note_path_id = fabrication_note_path.pcb_fabrication_note_path_id;
16359
16570
  }
16360
- };
16361
-
16362
- // lib/components/primitive-components/FabricationNoteText.ts
16363
- import { fabricationNoteTextProps } from "@tscircuit/props";
16364
- var FabricationNoteText = class extends PrimitiveComponent2 {
16365
- get config() {
16366
- return {
16367
- componentName: "FabricationNoteText",
16368
- zodProps: fabricationNoteTextProps
16369
- };
16571
+ _getSchematicSymbolDisplayValue() {
16572
+ return this._parsedProps.schDisplayValue || this._parsedProps.color || void 0;
16370
16573
  }
16371
- doInitialPcbPrimitiveRender() {
16372
- if (this.root?.pcbDisabled) return;
16574
+ getFootprinterString() {
16575
+ const baseFootprint = super.getFootprinterString();
16576
+ if (baseFootprint && this.props.color) {
16577
+ return `${baseFootprint}_color(${this.props.color})`;
16578
+ }
16579
+ return baseFootprint;
16580
+ }
16581
+ doInitialSourceRender() {
16373
16582
  const { db } = this.root;
16374
16583
  const { _parsedProps: props } = this;
16375
- const { pcbX, pcbY } = this.getResolvedPcbPositionProp();
16376
- const container = this.getPrimitiveContainer();
16377
- const subcircuit = this.getSubcircuit();
16378
- db.pcb_fabrication_note_text.insert({
16379
- anchor_alignment: props.anchorAlignment,
16380
- anchor_position: {
16381
- x: pcbX,
16382
- y: pcbY
16383
- },
16384
- font: props.font ?? "tscircuit2024",
16385
- font_size: props.fontSize ?? 1,
16386
- layer: "top",
16584
+ const source_component = db.source_component.insert({
16585
+ ftype: "simple_led",
16586
+ name: this.name,
16587
+ wave_length: props.wavelength,
16387
16588
  color: props.color,
16388
- text: props.text ?? "",
16389
- pcb_component_id: container.pcb_component_id,
16390
- subcircuit_id: subcircuit?.subcircuit_id ?? void 0,
16391
- pcb_group_id: this.getGroup()?.pcb_group_id ?? void 0
16589
+ symbol_display_value: this._getSchematicSymbolDisplayValue(),
16590
+ // @ts-ignore
16591
+ manufacturer_part_number: props.manufacturerPartNumber ?? props.mfn,
16592
+ supplier_part_numbers: props.supplierPartNumbers,
16593
+ are_pins_interchangeable: false
16392
16594
  });
16595
+ this.source_component_id = source_component.source_component_id;
16393
16596
  }
16597
+ pos = this.portMap.pin1;
16598
+ anode = this.portMap.pin1;
16599
+ neg = this.portMap.pin2;
16600
+ cathode = this.portMap.pin2;
16394
16601
  };
16395
16602
 
16396
- // lib/components/primitive-components/FabricationNoteDimension.ts
16397
- import { fabricationNoteDimensionProps } from "@tscircuit/props";
16398
- import { applyToPoint as applyToPoint11 } from "transformation-matrix";
16399
- var FabricationNoteDimension = class extends PrimitiveComponent2 {
16400
- fabrication_note_dimension_id = null;
16401
- isPcbPrimitive = true;
16603
+ // lib/components/normal-components/PowerSource.ts
16604
+ import { powerSourceProps } from "@tscircuit/props";
16605
+ var PowerSource = class extends NormalComponent3 {
16606
+ // @ts-ignore
16402
16607
  get config() {
16403
16608
  return {
16404
- componentName: "FabricationNoteDimension",
16405
- zodProps: fabricationNoteDimensionProps
16609
+ // TBD in schematic_symbol and replace then
16610
+ schematicSymbolName: this.props.symbolName ?? "power_factor_meter_horz",
16611
+ componentName: "PowerSource",
16612
+ zodProps: powerSourceProps,
16613
+ sourceFtype: "simple_power_source"
16406
16614
  };
16407
16615
  }
16408
- _resolvePoint(input, transform) {
16409
- if (typeof input === "string") {
16410
- const target = this.getSubcircuit().selectOne(
16411
- input
16412
- );
16413
- if (!target) {
16414
- this.renderError(
16415
- `FabricationNoteDimension could not find selector "${input}"`
16416
- );
16417
- return applyToPoint11(transform, { x: 0, y: 0 });
16418
- }
16419
- return target._getGlobalPcbPositionBeforeLayout();
16420
- }
16421
- const numericX = typeof input.x === "string" ? parseFloat(input.x) : input.x;
16422
- const numericY = typeof input.y === "string" ? parseFloat(input.y) : input.y;
16423
- return applyToPoint11(transform, { x: numericX, y: numericY });
16616
+ initPorts() {
16617
+ this.add(
16618
+ new Port({ name: "pin1", pinNumber: 1, aliases: ["positive", "pos"] })
16619
+ );
16620
+ this.add(
16621
+ new Port({ name: "pin2", pinNumber: 2, aliases: ["negative", "neg"] })
16622
+ );
16424
16623
  }
16425
- doInitialPcbPrimitiveRender() {
16426
- if (this.root?.pcbDisabled) return;
16624
+ doInitialSourceRender() {
16427
16625
  const { db } = this.root;
16428
16626
  const { _parsedProps: props } = this;
16429
- const transform = this._computePcbGlobalTransformBeforeLayout();
16430
- const from = this._resolvePoint(props.from, transform);
16431
- const to = this._resolvePoint(props.to, transform);
16432
- const subcircuit = this.getSubcircuit();
16433
- const group = this.getGroup();
16434
- const { maybeFlipLayer } = this._getPcbPrimitiveFlippedHelpers();
16435
- const layer = maybeFlipLayer(props.layer ?? "top");
16436
- if (layer !== "top" && layer !== "bottom") {
16437
- throw new Error(
16438
- `Invalid layer "${layer}" for FabricationNoteDimension. Must be "top" or "bottom".`
16439
- );
16440
- }
16441
- const pcb_component_id = this.parent?.pcb_component_id ?? this.getPrimitiveContainer()?.pcb_component_id;
16442
- const text = props.text ?? this._formatDistanceText({ from, to, units: props.units ?? "mm" });
16443
- const fabrication_note_dimension = db.pcb_fabrication_note_dimension.insert(
16444
- {
16445
- pcb_component_id,
16446
- subcircuit_id: subcircuit?.subcircuit_id ?? void 0,
16447
- pcb_group_id: group?.pcb_group_id ?? void 0,
16448
- layer,
16449
- from,
16450
- to,
16451
- text,
16452
- offset: props.offset,
16453
- font: props.font ?? "tscircuit2024",
16454
- font_size: props.fontSize ?? 1,
16455
- color: props.color,
16456
- arrow_size: props.arrowSize ?? 1
16457
- }
16458
- );
16459
- this.fabrication_note_dimension_id = fabrication_note_dimension.pcb_fabrication_note_dimension_id;
16460
- }
16461
- getPcbSize() {
16462
- const transform = this._computePcbGlobalTransformBeforeLayout();
16463
- const from = this._resolvePoint(this._parsedProps.from, transform);
16464
- const to = this._resolvePoint(this._parsedProps.to, transform);
16465
- return {
16466
- width: Math.abs(to.x - from.x),
16467
- height: Math.abs(to.y - from.y)
16468
- };
16469
- }
16470
- _formatDistanceText({
16471
- from,
16472
- to,
16473
- units
16474
- }) {
16475
- const dx = to.x - from.x;
16476
- const dy = to.y - from.y;
16477
- const distanceInMillimeters = Math.sqrt(dx * dx + dy * dy);
16478
- const distanceInUnits = units === "in" ? distanceInMillimeters / 25.4 : distanceInMillimeters;
16479
- const roundedDistance = Math.round(distanceInUnits);
16480
- const isWholeNumber = Math.abs(distanceInUnits - roundedDistance) < 1e-9;
16481
- if (isWholeNumber) {
16482
- return `${roundedDistance}${units}`;
16483
- }
16484
- const decimalPlaces = units === "in" ? 3 : 2;
16485
- const valueText = units === "in" ? Number(distanceInUnits.toFixed(decimalPlaces)).toString() : distanceInUnits.toFixed(decimalPlaces);
16486
- return `${valueText}${units}`;
16627
+ const source_component = db.source_component.insert({
16628
+ ftype: "simple_power_source",
16629
+ name: this.name,
16630
+ voltage: props.voltage,
16631
+ supplier_part_numbers: props.supplierPartNumbers,
16632
+ are_pins_interchangeable: false
16633
+ });
16634
+ this.source_component_id = source_component.source_component_id;
16487
16635
  }
16636
+ pos = this.portMap.pin1;
16637
+ positive = this.portMap.pin1;
16638
+ neg = this.portMap.pin2;
16639
+ negative = this.portMap.pin2;
16488
16640
  };
16489
16641
 
16490
- // lib/components/primitive-components/PcbNoteLine.ts
16491
- import { pcbNoteLineProps } from "@tscircuit/props";
16492
- import { applyToPoint as applyToPoint12 } from "transformation-matrix";
16493
- var PcbNoteLine = class extends PrimitiveComponent2 {
16494
- pcb_note_line_id = null;
16495
- isPcbPrimitive = true;
16642
+ // lib/components/normal-components/VoltageSource.ts
16643
+ import { voltageSourceProps } from "@tscircuit/props";
16644
+ var VoltageSource = class extends NormalComponent3 {
16496
16645
  get config() {
16646
+ const isSquare = this.props.waveShape === "square";
16497
16647
  return {
16498
- componentName: "PcbNoteLine",
16499
- zodProps: pcbNoteLineProps
16648
+ componentName: "VoltageSource",
16649
+ schematicSymbolName: isSquare ? "square_wave" : "ac_voltmeter",
16650
+ zodProps: voltageSourceProps,
16651
+ sourceFtype: "simple_voltage_source"
16500
16652
  };
16501
16653
  }
16502
- doInitialPcbPrimitiveRender() {
16503
- if (this.root?.pcbDisabled) return;
16654
+ runRenderPhaseForChildren(phase) {
16655
+ if (phase.startsWith("Pcb")) {
16656
+ return;
16657
+ }
16658
+ for (const child of this.children) {
16659
+ child.runRenderPhaseForChildren(phase);
16660
+ child.runRenderPhase(phase);
16661
+ }
16662
+ }
16663
+ doInitialPcbComponentRender() {
16664
+ }
16665
+ initPorts() {
16666
+ super.initPorts({
16667
+ additionalAliases: {
16668
+ pin1: ["terminal1"],
16669
+ pin2: ["terminal2"]
16670
+ }
16671
+ });
16672
+ }
16673
+ doInitialSourceRender() {
16504
16674
  const { db } = this.root;
16505
16675
  const { _parsedProps: props } = this;
16506
- const subcircuit = this.getSubcircuit();
16507
- const group = this.getGroup();
16508
- const transform = this._computePcbGlobalTransformBeforeLayout();
16509
- const start = applyToPoint12(transform, { x: props.x1, y: props.y1 });
16510
- const end = applyToPoint12(transform, { x: props.x2, y: props.y2 });
16511
- const pcb_component_id = this.parent?.pcb_component_id ?? this.getPrimitiveContainer()?.pcb_component_id ?? void 0;
16512
- const pcb_note_line = db.pcb_note_line.insert({
16513
- pcb_component_id,
16514
- subcircuit_id: subcircuit?.subcircuit_id ?? void 0,
16515
- pcb_group_id: group?.pcb_group_id ?? void 0,
16516
- x1: start.x,
16517
- y1: start.y,
16518
- x2: end.x,
16519
- y2: end.y,
16520
- stroke_width: props.strokeWidth ?? 0.1,
16521
- color: props.color,
16522
- is_dashed: props.isDashed
16676
+ const source_component = db.source_component.insert({
16677
+ ftype: "simple_voltage_source",
16678
+ name: this.name,
16679
+ voltage: props.voltage,
16680
+ frequency: props.frequency,
16681
+ peak_to_peak_voltage: props.peakToPeakVoltage,
16682
+ wave_shape: props.waveShape,
16683
+ phase: props.phase,
16684
+ duty_cycle: props.dutyCycle,
16685
+ supplier_part_numbers: props.supplierPartNumbers,
16686
+ are_pins_interchangeable: true
16523
16687
  });
16524
- this.pcb_note_line_id = pcb_note_line.pcb_note_line_id;
16688
+ this.source_component_id = source_component.source_component_id;
16525
16689
  }
16526
- getPcbSize() {
16690
+ doInitialSimulationRender() {
16691
+ const { db } = this.root;
16527
16692
  const { _parsedProps: props } = this;
16693
+ const terminal1Port = this.portMap.terminal1;
16694
+ const terminal2Port = this.portMap.terminal2;
16695
+ db.simulation_voltage_source.insert({
16696
+ type: "simulation_voltage_source",
16697
+ is_dc_source: false,
16698
+ terminal1_source_port_id: terminal1Port.source_port_id,
16699
+ terminal2_source_port_id: terminal2Port.source_port_id,
16700
+ voltage: props.voltage,
16701
+ frequency: props.frequency,
16702
+ peak_to_peak_voltage: props.peakToPeakVoltage,
16703
+ wave_shape: props.waveShape,
16704
+ phase: props.phase,
16705
+ duty_cycle: props.dutyCycle
16706
+ });
16707
+ }
16708
+ terminal1 = this.portMap.terminal1;
16709
+ terminal2 = this.portMap.terminal2;
16710
+ };
16711
+
16712
+ // lib/components/primitive-components/Constraint.ts
16713
+ import { constraintProps } from "@tscircuit/props";
16714
+ import "zod";
16715
+ var edgeSpecifiers = [
16716
+ "leftedge",
16717
+ "rightedge",
16718
+ "topedge",
16719
+ "bottomedge",
16720
+ "center"
16721
+ ];
16722
+ var Constraint3 = class extends PrimitiveComponent2 {
16723
+ get config() {
16528
16724
  return {
16529
- width: Math.abs(props.x2 - props.x1),
16530
- height: Math.abs(props.y2 - props.y1)
16725
+ componentName: "Constraint",
16726
+ zodProps: constraintProps
16531
16727
  };
16532
16728
  }
16729
+ constructor(props) {
16730
+ super(props);
16731
+ if ("xdist" in props || "ydist" in props) {
16732
+ if (!("edgeToEdge" in props) && !("centerToCenter" in props)) {
16733
+ throw new Error(
16734
+ `edgeToEdge, centerToCenter must be set for xDist or yDist for ${this}`
16735
+ );
16736
+ }
16737
+ }
16738
+ if ("for" in props && props.for.length < 2) {
16739
+ throw new Error(`"for" must have at least two selectors for ${this}`);
16740
+ }
16741
+ }
16742
+ _getAllReferencedComponents() {
16743
+ const componentsWithSelectors = [];
16744
+ const container = this.getPrimitiveContainer();
16745
+ function addComponentFromSelector(selector) {
16746
+ const maybeEdge = selector.split(" ").pop();
16747
+ const edge = edgeSpecifiers.includes(maybeEdge) ? maybeEdge : void 0;
16748
+ const componentSelector = edge ? selector.replace(` ${edge}`, "") : selector;
16749
+ const component = container.selectOne(componentSelector, {
16750
+ pcbPrimitive: true
16751
+ });
16752
+ if (component) {
16753
+ componentsWithSelectors.push({
16754
+ selector,
16755
+ component,
16756
+ componentSelector,
16757
+ edge
16758
+ });
16759
+ }
16760
+ }
16761
+ for (const key of ["left", "right", "top", "bottom"]) {
16762
+ if (key in this._parsedProps) {
16763
+ addComponentFromSelector(this._parsedProps[key]);
16764
+ }
16765
+ }
16766
+ if ("for" in this._parsedProps) {
16767
+ for (const selector of this._parsedProps.for) {
16768
+ addComponentFromSelector(selector);
16769
+ }
16770
+ }
16771
+ return { componentsWithSelectors };
16772
+ }
16533
16773
  };
16534
16774
 
16535
- // lib/components/primitive-components/PcbNoteRect.ts
16536
- import { pcbNoteRectProps } from "@tscircuit/props";
16537
- import { applyToPoint as applyToPoint13 } from "transformation-matrix";
16538
- var PcbNoteRect = class extends PrimitiveComponent2 {
16539
- pcb_note_rect_id = null;
16540
- isPcbPrimitive = true;
16775
+ // lib/components/primitive-components/FabricationNoteRect.ts
16776
+ import { fabricationNoteRectProps } from "@tscircuit/props";
16777
+ import "transformation-matrix";
16778
+ var FabricationNoteRect = class extends PrimitiveComponent2 {
16779
+ fabrication_note_rect_id = null;
16541
16780
  get config() {
16542
16781
  return {
16543
- componentName: "PcbNoteRect",
16544
- zodProps: pcbNoteRectProps
16782
+ componentName: "FabricationNoteRect",
16783
+ zodProps: fabricationNoteRectProps
16545
16784
  };
16546
16785
  }
16547
16786
  doInitialPcbPrimitiveRender() {
16548
16787
  if (this.root?.pcbDisabled) return;
16549
16788
  const { db } = this.root;
16550
16789
  const { _parsedProps: props } = this;
16551
- const transform = this._computePcbGlobalTransformBeforeLayout();
16552
- const center = applyToPoint13(transform, { x: 0, y: 0 });
16790
+ const { pcbX, pcbY } = this.getResolvedPcbPositionProp();
16791
+ const { maybeFlipLayer } = this._getPcbPrimitiveFlippedHelpers();
16792
+ const layer = maybeFlipLayer(props.layer ?? "top");
16793
+ if (layer !== "top" && layer !== "bottom") {
16794
+ throw new Error(
16795
+ `Invalid layer "${layer}" for FabricationNoteRect. Must be "top" or "bottom".`
16796
+ );
16797
+ }
16798
+ const pcb_component_id = this.parent?.pcb_component_id ?? this.getPrimitiveContainer()?.pcb_component_id;
16553
16799
  const subcircuit = this.getSubcircuit();
16554
- const group = this.getGroup();
16555
- const pcb_component_id = this.parent?.pcb_component_id ?? this.getPrimitiveContainer()?.pcb_component_id ?? void 0;
16556
- const pcb_note_rect = db.pcb_note_rect.insert({
16800
+ const hasStroke = props.hasStroke ?? (props.strokeWidth !== void 0 && props.strokeWidth !== null);
16801
+ const fabrication_note_rect = db.pcb_fabrication_note_rect.insert({
16557
16802
  pcb_component_id,
16558
- subcircuit_id: subcircuit?.subcircuit_id ?? void 0,
16559
- pcb_group_id: group?.pcb_group_id ?? void 0,
16560
- center,
16803
+ layer,
16804
+ color: props.color,
16805
+ center: {
16806
+ x: pcbX,
16807
+ y: pcbY
16808
+ },
16561
16809
  width: props.width,
16562
16810
  height: props.height,
16563
- stroke_width: props.strokeWidth ?? 0.1,
16811
+ stroke_width: props.strokeWidth ?? 1,
16564
16812
  is_filled: props.isFilled ?? false,
16565
- has_stroke: props.hasStroke ?? true,
16813
+ has_stroke: hasStroke,
16566
16814
  is_stroke_dashed: props.isStrokeDashed ?? false,
16567
- color: props.color,
16815
+ subcircuit_id: subcircuit?.subcircuit_id ?? void 0,
16816
+ pcb_group_id: this.getGroup()?.pcb_group_id ?? void 0,
16568
16817
  corner_radius: props.cornerRadius ?? void 0
16569
16818
  });
16570
- this.pcb_note_rect_id = pcb_note_rect.pcb_note_rect_id;
16819
+ this.fabrication_note_rect_id = fabrication_note_rect.pcb_fabrication_note_rect_id;
16571
16820
  }
16572
16821
  getPcbSize() {
16573
16822
  const { _parsedProps: props } = this;
16574
- const width = typeof props.width === "string" ? parseFloat(props.width) : props.width;
16575
- const height = typeof props.height === "string" ? parseFloat(props.height) : props.height;
16576
- return { width, height };
16823
+ return { width: props.width, height: props.height };
16577
16824
  }
16578
16825
  };
16579
16826
 
16580
- // lib/components/primitive-components/PcbNoteText.ts
16581
- import { pcbNoteTextProps } from "@tscircuit/props";
16582
- import { applyToPoint as applyToPoint14 } from "transformation-matrix";
16583
- var PcbNoteText = class extends PrimitiveComponent2 {
16584
- pcb_note_text_id = null;
16585
- isPcbPrimitive = true;
16827
+ // lib/components/primitive-components/FabricationNotePath.ts
16828
+ import { fabricationNotePathProps } from "@tscircuit/props";
16829
+ import { applyToPoint as applyToPoint10 } from "transformation-matrix";
16830
+ var FabricationNotePath = class extends PrimitiveComponent2 {
16831
+ fabrication_note_path_id = null;
16586
16832
  get config() {
16587
16833
  return {
16588
- componentName: "PcbNoteText",
16589
- zodProps: pcbNoteTextProps
16834
+ componentName: "FabricationNotePath",
16835
+ zodProps: fabricationNotePathProps
16590
16836
  };
16591
16837
  }
16592
16838
  doInitialPcbPrimitiveRender() {
16593
16839
  if (this.root?.pcbDisabled) return;
16594
16840
  const { db } = this.root;
16841
+ const subcircuit = this.getSubcircuit();
16595
16842
  const { _parsedProps: props } = this;
16843
+ const layer = props.layer ?? "top";
16844
+ if (layer !== "top" && layer !== "bottom") {
16845
+ throw new Error(
16846
+ `Invalid layer "${layer}" for SilkscreenPath. Must be "top" or "bottom".`
16847
+ );
16848
+ }
16596
16849
  const transform = this._computePcbGlobalTransformBeforeLayout();
16597
- const anchorPosition = applyToPoint14(transform, { x: 0, y: 0 });
16598
- const subcircuit = this.getSubcircuit();
16599
- const group = this.getGroup();
16600
- const pcb_component_id = this.parent?.pcb_component_id ?? this.getPrimitiveContainer()?.pcb_component_id ?? void 0;
16601
- const pcb_note_text = db.pcb_note_text.insert({
16850
+ const pcb_component_id = this.parent?.pcb_component_id ?? this.getPrimitiveContainer()?.pcb_component_id;
16851
+ const fabrication_note_path = db.pcb_fabrication_note_path.insert({
16602
16852
  pcb_component_id,
16603
- subcircuit_id: subcircuit?.subcircuit_id ?? void 0,
16604
- pcb_group_id: group?.pcb_group_id ?? void 0,
16605
- font: props.font ?? "tscircuit2024",
16606
- font_size: props.fontSize ?? 1,
16607
- text: props.text,
16608
- anchor_position: anchorPosition,
16609
- anchor_alignment: props.anchorAlignment ?? "center",
16610
- color: props.color
16853
+ layer,
16854
+ color: props.color,
16855
+ route: props.route.map((p) => {
16856
+ const transformedPosition = applyToPoint10(transform, {
16857
+ x: p.x,
16858
+ y: p.y
16859
+ });
16860
+ return {
16861
+ ...p,
16862
+ x: transformedPosition.x,
16863
+ y: transformedPosition.y
16864
+ };
16865
+ }),
16866
+ stroke_width: props.strokeWidth ?? 0.1,
16867
+ subcircuit_id: subcircuit?.subcircuit_id ?? void 0
16611
16868
  });
16612
- this.pcb_note_text_id = pcb_note_text.pcb_note_text_id;
16613
- }
16614
- getPcbSize() {
16615
- const { _parsedProps: props } = this;
16616
- const fontSize = typeof props.fontSize === "string" ? parseFloat(props.fontSize) : props.fontSize ?? 1;
16617
- const charWidth = fontSize * 0.6;
16618
- const width = props.text.length * charWidth;
16619
- const height = fontSize;
16620
- return { width, height };
16869
+ this.fabrication_note_path_id = fabrication_note_path.pcb_fabrication_note_path_id;
16621
16870
  }
16622
16871
  };
16623
16872
 
16624
- // lib/components/primitive-components/PcbNotePath.ts
16625
- import { pcbNotePathProps } from "@tscircuit/props";
16626
- import { applyToPoint as applyToPoint15 } from "transformation-matrix";
16627
- var PcbNotePath = class extends PrimitiveComponent2 {
16628
- pcb_note_path_id = null;
16629
- isPcbPrimitive = true;
16873
+ // lib/components/primitive-components/FabricationNoteText.ts
16874
+ import { fabricationNoteTextProps } from "@tscircuit/props";
16875
+ var FabricationNoteText = class extends PrimitiveComponent2 {
16630
16876
  get config() {
16631
16877
  return {
16632
- componentName: "PcbNotePath",
16633
- zodProps: pcbNotePathProps
16878
+ componentName: "FabricationNoteText",
16879
+ zodProps: fabricationNoteTextProps
16634
16880
  };
16635
16881
  }
16636
16882
  doInitialPcbPrimitiveRender() {
16637
16883
  if (this.root?.pcbDisabled) return;
16638
16884
  const { db } = this.root;
16639
16885
  const { _parsedProps: props } = this;
16640
- const transform = this._computePcbGlobalTransformBeforeLayout();
16886
+ const { pcbX, pcbY } = this.getResolvedPcbPositionProp();
16887
+ const container = this.getPrimitiveContainer();
16641
16888
  const subcircuit = this.getSubcircuit();
16642
- const group = this.getGroup();
16643
- const pcb_component_id = this.parent?.pcb_component_id ?? this.getPrimitiveContainer()?.pcb_component_id ?? void 0;
16644
- const transformedRoute = props.route.map((point) => {
16645
- const { x, y, ...rest } = point;
16646
- const numericX = typeof x === "string" ? parseFloat(x) : x;
16647
- const numericY = typeof y === "string" ? parseFloat(y) : y;
16648
- const transformed = applyToPoint15(transform, { x: numericX, y: numericY });
16649
- return { ...rest, x: transformed.x, y: transformed.y };
16650
- });
16651
- const pcb_note_path = db.pcb_note_path.insert({
16652
- pcb_component_id,
16889
+ db.pcb_fabrication_note_text.insert({
16890
+ anchor_alignment: props.anchorAlignment,
16891
+ anchor_position: {
16892
+ x: pcbX,
16893
+ y: pcbY
16894
+ },
16895
+ font: props.font ?? "tscircuit2024",
16896
+ font_size: props.fontSize ?? 1,
16897
+ layer: "top",
16898
+ color: props.color,
16899
+ text: props.text ?? "",
16900
+ pcb_component_id: container.pcb_component_id,
16653
16901
  subcircuit_id: subcircuit?.subcircuit_id ?? void 0,
16654
- pcb_group_id: group?.pcb_group_id ?? void 0,
16655
- route: transformedRoute,
16656
- stroke_width: props.strokeWidth ?? 0.1,
16657
- color: props.color
16902
+ pcb_group_id: this.getGroup()?.pcb_group_id ?? void 0
16658
16903
  });
16659
- this.pcb_note_path_id = pcb_note_path.pcb_note_path_id;
16660
- }
16661
- getPcbSize() {
16662
- const { _parsedProps: props } = this;
16663
- if (props.route.length === 0) return { width: 0, height: 0 };
16664
- const xs = props.route.map(
16665
- (point) => typeof point.x === "string" ? parseFloat(point.x) : point.x
16666
- );
16667
- const ys = props.route.map(
16668
- (point) => typeof point.y === "string" ? parseFloat(point.y) : point.y
16669
- );
16670
- const minX = Math.min(...xs);
16671
- const maxX = Math.max(...xs);
16672
- const minY = Math.min(...ys);
16673
- const maxY = Math.max(...ys);
16674
- return { width: maxX - minX, height: maxY - minY };
16675
16904
  }
16676
16905
  };
16677
16906
 
16678
- // lib/components/primitive-components/PcbNoteDimension.ts
16679
- import { pcbNoteDimensionProps } from "@tscircuit/props";
16680
- import { applyToPoint as applyToPoint16 } from "transformation-matrix";
16681
- var PcbNoteDimension = class extends PrimitiveComponent2 {
16682
- pcb_note_dimension_id = null;
16907
+ // lib/components/primitive-components/FabricationNoteDimension.ts
16908
+ import { fabricationNoteDimensionProps } from "@tscircuit/props";
16909
+ import { applyToPoint as applyToPoint11 } from "transformation-matrix";
16910
+ var FabricationNoteDimension = class extends PrimitiveComponent2 {
16911
+ fabrication_note_dimension_id = null;
16683
16912
  isPcbPrimitive = true;
16684
16913
  get config() {
16685
16914
  return {
16686
- componentName: "PcbNoteDimension",
16687
- zodProps: pcbNoteDimensionProps
16915
+ componentName: "FabricationNoteDimension",
16916
+ zodProps: fabricationNoteDimensionProps
16688
16917
  };
16689
16918
  }
16690
16919
  _resolvePoint(input, transform) {
16691
16920
  if (typeof input === "string") {
16692
16921
  const target = this.getSubcircuit().selectOne(
16693
- `.${input}`
16922
+ input
16694
16923
  );
16695
- if (!target) {
16696
- this.renderError(`PcbNoteDimension could not find selector "${input}"`);
16697
- return applyToPoint16(transform, { x: 0, y: 0 });
16924
+ if (!target) {
16925
+ this.renderError(
16926
+ `FabricationNoteDimension could not find selector "${input}"`
16927
+ );
16928
+ return applyToPoint11(transform, { x: 0, y: 0 });
16698
16929
  }
16699
16930
  return target._getGlobalPcbPositionBeforeLayout();
16700
16931
  }
16701
16932
  const numericX = typeof input.x === "string" ? parseFloat(input.x) : input.x;
16702
16933
  const numericY = typeof input.y === "string" ? parseFloat(input.y) : input.y;
16703
- return applyToPoint16(transform, { x: numericX, y: numericY });
16934
+ return applyToPoint11(transform, { x: numericX, y: numericY });
16704
16935
  }
16705
16936
  doInitialPcbPrimitiveRender() {
16706
16937
  if (this.root?.pcbDisabled) return;
@@ -16711,506 +16942,333 @@ var PcbNoteDimension = class extends PrimitiveComponent2 {
16711
16942
  const to = this._resolvePoint(props.to, transform);
16712
16943
  const subcircuit = this.getSubcircuit();
16713
16944
  const group = this.getGroup();
16714
- const pcb_component_id = this.parent?.pcb_component_id ?? this.getPrimitiveContainer()?.pcb_component_id ?? void 0;
16715
- const text = props.text ?? this._formatDistanceText({ from, to, units: props.units ?? "mm" });
16716
- const pcb_note_dimension = db.pcb_note_dimension.insert({
16717
- pcb_component_id,
16718
- subcircuit_id: subcircuit?.subcircuit_id ?? void 0,
16719
- pcb_group_id: group?.pcb_group_id ?? void 0,
16720
- from,
16721
- to,
16722
- text,
16723
- font: props.font ?? "tscircuit2024",
16724
- font_size: props.fontSize ?? 1,
16725
- color: props.color,
16726
- arrow_size: props.arrowSize ?? 1
16727
- });
16728
- this.pcb_note_dimension_id = pcb_note_dimension.pcb_note_dimension_id;
16729
- }
16730
- getPcbSize() {
16731
- const transform = this._computePcbGlobalTransformBeforeLayout();
16732
- const from = this._resolvePoint(this._parsedProps.from, transform);
16733
- const to = this._resolvePoint(this._parsedProps.to, transform);
16734
- return {
16735
- width: Math.abs(to.x - from.x),
16736
- height: Math.abs(to.y - from.y)
16737
- };
16738
- }
16739
- _formatDistanceText({
16740
- from,
16741
- to,
16742
- units
16743
- }) {
16744
- const dx = to.x - from.x;
16745
- const dy = to.y - from.y;
16746
- const distanceInMillimeters = Math.sqrt(dx * dx + dy * dy);
16747
- const distanceInUnits = units === "in" ? distanceInMillimeters / 25.4 : distanceInMillimeters;
16748
- const roundedDistance = Math.round(distanceInUnits);
16749
- const isWholeNumber = Math.abs(distanceInUnits - roundedDistance) < 1e-9;
16750
- if (isWholeNumber) {
16751
- return `${roundedDistance}${units}`;
16752
- }
16753
- const decimalPlaces = units === "in" ? 3 : 2;
16754
- const valueText = units === "in" ? Number(distanceInUnits.toFixed(decimalPlaces)).toString() : distanceInUnits.toFixed(decimalPlaces);
16755
- return `${valueText}${units}`;
16756
- }
16757
- };
16758
-
16759
- // lib/components/primitive-components/Group/Subcircuit/Subcircuit.ts
16760
- import "@tscircuit/props";
16761
- import { cju } from "@tscircuit/circuit-json-util";
16762
-
16763
- // lib/components/primitive-components/Group/Subcircuit/inflators/inflatePcbComponent.ts
16764
- import { compose as compose5, translate as translate6, rotate as rotate3, inverse } from "transformation-matrix";
16765
- import { transformPCBElements as transformPCBElements2 } from "@tscircuit/circuit-json-util";
16766
- var inflatePcbComponent = (pcbElm, inflatorContext) => {
16767
- const { injectionDb, normalComponent } = inflatorContext;
16768
- if (!normalComponent) return;
16769
- const componentCenter = pcbElm.center || { x: 0, y: 0 };
16770
- const componentRotation = pcbElm.rotation || 0;
16771
- const absoluteToComponentRelativeTransform = inverse(
16772
- compose5(
16773
- translate6(componentCenter.x, componentCenter.y),
16774
- rotate3(componentRotation * Math.PI / 180)
16775
- )
16776
- );
16777
- const relativeElements = injectionDb.toArray().filter(
16778
- (elm) => "pcb_component_id" in elm && elm.pcb_component_id === pcbElm.pcb_component_id
16779
- );
16780
- transformPCBElements2(relativeElements, absoluteToComponentRelativeTransform);
16781
- const components = createComponentsFromCircuitJson(
16782
- {
16783
- componentName: normalComponent.name,
16784
- componentRotation: "0deg"
16785
- },
16786
- relativeElements
16787
- );
16788
- normalComponent.addAll(components);
16789
- };
16790
-
16791
- // lib/components/primitive-components/Group/Subcircuit/inflators/inflateSourceResistor.ts
16792
- function inflateSourceResistor(sourceElm, inflatorContext) {
16793
- const { injectionDb, subcircuit, groupsMap } = inflatorContext;
16794
- const pcbElm = injectionDb.pcb_component.getWhere({
16795
- source_component_id: sourceElm.source_component_id
16796
- });
16797
- const cadElm = injectionDb.cad_component.getWhere({
16798
- source_component_id: sourceElm.source_component_id
16799
- });
16800
- const resistor = new Resistor({
16801
- name: sourceElm.name,
16802
- resistance: sourceElm.resistance,
16803
- layer: pcbElm?.layer,
16804
- pcbX: pcbElm?.center?.x,
16805
- pcbY: pcbElm?.center?.y,
16806
- pcbRotation: pcbElm?.rotation,
16807
- doNotPlace: pcbElm?.do_not_place,
16808
- obstructsWithinBounds: pcbElm?.obstructs_within_bounds
16809
- });
16810
- if (pcbElm) {
16811
- inflatePcbComponent(pcbElm, {
16812
- ...inflatorContext,
16813
- normalComponent: resistor
16814
- });
16815
- }
16816
- if (sourceElm.source_group_id && groupsMap?.has(sourceElm.source_group_id)) {
16817
- const group = groupsMap.get(sourceElm.source_group_id);
16818
- group.add(resistor);
16819
- } else {
16820
- subcircuit.add(resistor);
16821
- }
16822
- }
16823
-
16824
- // lib/components/primitive-components/Group/Subcircuit/inflators/inflateSourcePort.ts
16825
- function inflateSourcePort(sourcePort, inflatorContext) {
16826
- const { injectionDb, subcircuit } = inflatorContext;
16827
- if (sourcePort.source_component_id !== null) {
16828
- return;
16829
- }
16830
- const pcbPortFromInjection = injectionDb.pcb_port.getWhere({
16831
- source_port_id: sourcePort.source_port_id
16832
- });
16833
- const port = new Port({
16834
- name: sourcePort.name,
16835
- pinNumber: sourcePort.pin_number
16836
- });
16837
- subcircuit.add(port);
16838
- port.source_port_id = sourcePort.source_port_id;
16839
- const root = subcircuit.root;
16840
- if (root && pcbPortFromInjection) {
16841
- const { db } = root;
16842
- const pcb_port = db.pcb_port.insert({
16843
- pcb_component_id: void 0,
16844
- layers: pcbPortFromInjection.layers,
16845
- subcircuit_id: subcircuit.subcircuit_id ?? void 0,
16846
- pcb_group_id: subcircuit.getGroup()?.pcb_group_id ?? void 0,
16847
- x: pcbPortFromInjection.x,
16848
- y: pcbPortFromInjection.y,
16849
- source_port_id: sourcePort.source_port_id,
16850
- is_board_pinout: false
16851
- });
16852
- port.pcb_port_id = pcb_port.pcb_port_id;
16853
- }
16854
- }
16855
-
16856
- // lib/components/primitive-components/Group/Subcircuit/inflators/inflateSourceGroup.ts
16857
- function inflateSourceGroup(sourceGroup, inflatorContext) {
16858
- const { subcircuit, groupsMap } = inflatorContext;
16859
- const group = new Group6({
16860
- name: sourceGroup.name
16861
- });
16862
- group.source_group_id = sourceGroup.source_group_id;
16863
- subcircuit.add(group);
16864
- if (groupsMap) {
16865
- groupsMap.set(sourceGroup.source_group_id, group);
16866
- }
16867
- return group;
16868
- }
16869
-
16870
- // lib/components/primitive-components/Group/Subcircuit/inflators/inflateSourceChip.ts
16871
- var mapInternallyConnectedSourcePortIdsToPinLabels = (sourcePortIds, inflatorContext) => {
16872
- if (!sourcePortIds || sourcePortIds.length === 0) return void 0;
16873
- const { injectionDb } = inflatorContext;
16874
- const mapped = sourcePortIds.map(
16875
- (group) => group.map((sourcePortId) => {
16876
- const port = injectionDb.source_port.get(
16877
- sourcePortId
16945
+ const { maybeFlipLayer } = this._getPcbPrimitiveFlippedHelpers();
16946
+ const layer = maybeFlipLayer(props.layer ?? "top");
16947
+ if (layer !== "top" && layer !== "bottom") {
16948
+ throw new Error(
16949
+ `Invalid layer "${layer}" for FabricationNoteDimension. Must be "top" or "bottom".`
16878
16950
  );
16879
- if (!port) return null;
16880
- if (port.pin_number !== void 0 && port.pin_number !== null) {
16881
- return `pin${port.pin_number}`;
16882
- }
16883
- return port.name;
16884
- }).filter((value) => value !== null)
16885
- ).filter((group) => group.length > 0);
16886
- return mapped.length > 0 ? mapped : void 0;
16887
- };
16888
- var inflateSourceChip = (sourceElm, inflatorContext) => {
16889
- const { injectionDb, subcircuit, groupsMap } = inflatorContext;
16890
- const pcbElm = injectionDb.pcb_component.getWhere({
16891
- source_component_id: sourceElm.source_component_id
16892
- });
16893
- const schematicElm = injectionDb.schematic_component.getWhere({
16894
- source_component_id: sourceElm.source_component_id
16895
- });
16896
- const cadElm = injectionDb.cad_component.getWhere({
16897
- source_component_id: sourceElm.source_component_id
16898
- });
16899
- const internallyConnectedPins = mapInternallyConnectedSourcePortIdsToPinLabels(
16900
- sourceElm.internally_connected_source_port_ids,
16901
- inflatorContext
16902
- );
16903
- const chip = new Chip({
16904
- name: sourceElm.name,
16905
- manufacturerPartNumber: sourceElm.manufacturer_part_number,
16906
- supplierPartNumbers: sourceElm.supplier_part_numbers ?? void 0,
16907
- pinLabels: schematicElm?.port_labels ?? void 0,
16908
- schWidth: schematicElm?.size?.width,
16909
- schHeight: schematicElm?.size?.height,
16910
- schPinSpacing: schematicElm?.pin_spacing,
16911
- schX: schematicElm?.center?.x,
16912
- schY: schematicElm?.center?.y,
16913
- layer: pcbElm?.layer,
16914
- pcbX: pcbElm?.center?.x,
16915
- pcbY: pcbElm?.center?.y,
16916
- pcbRotation: pcbElm?.rotation,
16917
- doNotPlace: pcbElm?.do_not_place,
16918
- obstructsWithinBounds: pcbElm?.obstructs_within_bounds,
16919
- internallyConnectedPins
16920
- });
16921
- const footprint = cadElm?.footprinter_string ?? null;
16922
- if (footprint) {
16923
- Object.assign(chip.props, { footprint });
16924
- Object.assign(chip._parsedProps, { footprint });
16925
- if (!cadElm) {
16926
- ;
16927
- chip._addChildrenFromStringFootprint?.();
16928
16951
  }
16952
+ const pcb_component_id = this.parent?.pcb_component_id ?? this.getPrimitiveContainer()?.pcb_component_id;
16953
+ const text = props.text ?? this._formatDistanceText({ from, to, units: props.units ?? "mm" });
16954
+ const fabrication_note_dimension = db.pcb_fabrication_note_dimension.insert(
16955
+ {
16956
+ pcb_component_id,
16957
+ subcircuit_id: subcircuit?.subcircuit_id ?? void 0,
16958
+ pcb_group_id: group?.pcb_group_id ?? void 0,
16959
+ layer,
16960
+ from,
16961
+ to,
16962
+ text,
16963
+ offset: props.offset,
16964
+ font: props.font ?? "tscircuit2024",
16965
+ font_size: props.fontSize ?? 1,
16966
+ color: props.color,
16967
+ arrow_size: props.arrowSize ?? 1
16968
+ }
16969
+ );
16970
+ this.fabrication_note_dimension_id = fabrication_note_dimension.pcb_fabrication_note_dimension_id;
16929
16971
  }
16930
- if (pcbElm) {
16931
- inflatePcbComponent(pcbElm, {
16932
- ...inflatorContext,
16933
- normalComponent: chip
16934
- });
16935
- }
16936
- if (sourceElm.source_group_id && groupsMap?.has(sourceElm.source_group_id)) {
16937
- const group = groupsMap.get(sourceElm.source_group_id);
16938
- group.add(chip);
16939
- } else {
16940
- subcircuit.add(chip);
16941
- }
16942
- };
16943
-
16944
- // lib/components/primitive-components/Group/Subcircuit/inflators/inflateSourceCapacitor.ts
16945
- function inflateSourceCapacitor(sourceElm, inflatorContext) {
16946
- const { injectionDb, subcircuit, groupsMap } = inflatorContext;
16947
- const pcbElm = injectionDb.pcb_component.getWhere({
16948
- source_component_id: sourceElm.source_component_id
16949
- });
16950
- const cadElm = injectionDb.cad_component.getWhere({
16951
- source_component_id: sourceElm.source_component_id
16952
- });
16953
- const capacitor = new Capacitor({
16954
- name: sourceElm.name,
16955
- capacitance: sourceElm.capacitance,
16956
- layer: pcbElm?.layer,
16957
- pcbX: pcbElm?.center?.x,
16958
- pcbY: pcbElm?.center?.y,
16959
- pcbRotation: pcbElm?.rotation,
16960
- doNotPlace: pcbElm?.do_not_place,
16961
- obstructsWithinBounds: pcbElm?.obstructs_within_bounds
16962
- });
16963
- if (pcbElm) {
16964
- inflatePcbComponent(pcbElm, {
16965
- ...inflatorContext,
16966
- normalComponent: capacitor
16967
- });
16972
+ getPcbSize() {
16973
+ const transform = this._computePcbGlobalTransformBeforeLayout();
16974
+ const from = this._resolvePoint(this._parsedProps.from, transform);
16975
+ const to = this._resolvePoint(this._parsedProps.to, transform);
16976
+ return {
16977
+ width: Math.abs(to.x - from.x),
16978
+ height: Math.abs(to.y - from.y)
16979
+ };
16968
16980
  }
16969
- if (sourceElm.source_group_id && groupsMap?.has(sourceElm.source_group_id)) {
16970
- const group = groupsMap.get(sourceElm.source_group_id);
16971
- group.add(capacitor);
16972
- } else {
16973
- subcircuit.add(capacitor);
16981
+ _formatDistanceText({
16982
+ from,
16983
+ to,
16984
+ units
16985
+ }) {
16986
+ const dx = to.x - from.x;
16987
+ const dy = to.y - from.y;
16988
+ const distanceInMillimeters = Math.sqrt(dx * dx + dy * dy);
16989
+ const distanceInUnits = units === "in" ? distanceInMillimeters / 25.4 : distanceInMillimeters;
16990
+ const roundedDistance = Math.round(distanceInUnits);
16991
+ const isWholeNumber = Math.abs(distanceInUnits - roundedDistance) < 1e-9;
16992
+ if (isWholeNumber) {
16993
+ return `${roundedDistance}${units}`;
16994
+ }
16995
+ const decimalPlaces = units === "in" ? 3 : 2;
16996
+ const valueText = units === "in" ? Number(distanceInUnits.toFixed(decimalPlaces)).toString() : distanceInUnits.toFixed(decimalPlaces);
16997
+ return `${valueText}${units}`;
16974
16998
  }
16975
- }
16999
+ };
16976
17000
 
16977
- // lib/components/normal-components/Inductor.ts
16978
- import { inductorProps } from "@tscircuit/props";
16979
- import { formatSiUnit as formatSiUnit4 } from "format-si-unit";
16980
- var Inductor = class extends NormalComponent3 {
16981
- _adjustSilkscreenTextAutomatically = true;
17001
+ // lib/components/primitive-components/PcbNoteLine.ts
17002
+ import { pcbNoteLineProps } from "@tscircuit/props";
17003
+ import { applyToPoint as applyToPoint12 } from "transformation-matrix";
17004
+ var PcbNoteLine = class extends PrimitiveComponent2 {
17005
+ pcb_note_line_id = null;
17006
+ isPcbPrimitive = true;
16982
17007
  get config() {
16983
17008
  return {
16984
- componentName: "Inductor",
16985
- schematicSymbolName: this.props.symbolName ?? "inductor",
16986
- zodProps: inductorProps,
16987
- sourceFtype: FTYPE.simple_inductor
17009
+ componentName: "PcbNoteLine",
17010
+ zodProps: pcbNoteLineProps
16988
17011
  };
16989
17012
  }
16990
- _getSchematicSymbolDisplayValue() {
16991
- return `${formatSiUnit4(this._parsedProps.inductance)}H`;
16992
- }
16993
- initPorts() {
16994
- super.initPorts({
16995
- additionalAliases: {
16996
- pin1: ["anode", "pos", "left"],
16997
- pin2: ["cathode", "neg", "right"]
16998
- }
16999
- });
17000
- }
17001
- doInitialSourceRender() {
17013
+ doInitialPcbPrimitiveRender() {
17014
+ if (this.root?.pcbDisabled) return;
17002
17015
  const { db } = this.root;
17003
17016
  const { _parsedProps: props } = this;
17004
- const source_component = db.source_component.insert({
17005
- name: this.name,
17006
- ftype: FTYPE.simple_inductor,
17007
- inductance: props.inductance,
17008
- supplier_part_numbers: props.supplierPartNumbers,
17009
- are_pins_interchangeable: true
17010
- });
17011
- this.source_component_id = source_component.source_component_id;
17012
- }
17013
- };
17014
-
17015
- // lib/components/primitive-components/Group/Subcircuit/inflators/inflateSourceInductor.ts
17016
- function inflateSourceInductor(sourceElm, inflatorContext) {
17017
- const { injectionDb, subcircuit, groupsMap } = inflatorContext;
17018
- const pcbElm = injectionDb.pcb_component.getWhere({
17019
- source_component_id: sourceElm.source_component_id
17020
- });
17021
- const cadElm = injectionDb.cad_component.getWhere({
17022
- source_component_id: sourceElm.source_component_id
17023
- });
17024
- const inductor = new Inductor({
17025
- name: sourceElm.name,
17026
- inductance: sourceElm.inductance,
17027
- layer: pcbElm?.layer,
17028
- pcbX: pcbElm?.center?.x,
17029
- pcbY: pcbElm?.center?.y,
17030
- pcbRotation: pcbElm?.rotation,
17031
- doNotPlace: pcbElm?.do_not_place,
17032
- obstructsWithinBounds: pcbElm?.obstructs_within_bounds
17033
- });
17034
- if (pcbElm) {
17035
- inflatePcbComponent(pcbElm, {
17036
- ...inflatorContext,
17037
- normalComponent: inductor
17038
- });
17039
- }
17040
- if (sourceElm.source_group_id && groupsMap?.has(sourceElm.source_group_id)) {
17041
- const group = groupsMap.get(sourceElm.source_group_id);
17042
- group.add(inductor);
17043
- } else {
17044
- subcircuit.add(inductor);
17045
- }
17046
- }
17047
-
17048
- // lib/components/primitive-components/Group/Subcircuit/inflators/inflateSourceDiode.ts
17049
- function inflateSourceDiode(sourceElm, inflatorContext) {
17050
- const { injectionDb, subcircuit, groupsMap } = inflatorContext;
17051
- const pcbElm = injectionDb.pcb_component.getWhere({
17052
- source_component_id: sourceElm.source_component_id
17053
- });
17054
- const cadElm = injectionDb.cad_component.getWhere({
17055
- source_component_id: sourceElm.source_component_id
17056
- });
17057
- const diode = new Diode({
17058
- name: sourceElm.name,
17059
- layer: pcbElm?.layer,
17060
- pcbX: pcbElm?.center?.x,
17061
- pcbY: pcbElm?.center?.y,
17062
- pcbRotation: pcbElm?.rotation,
17063
- doNotPlace: pcbElm?.do_not_place,
17064
- obstructsWithinBounds: pcbElm?.obstructs_within_bounds
17065
- });
17066
- if (pcbElm) {
17067
- inflatePcbComponent(pcbElm, {
17068
- ...inflatorContext,
17069
- normalComponent: diode
17017
+ const subcircuit = this.getSubcircuit();
17018
+ const group = this.getGroup();
17019
+ const transform = this._computePcbGlobalTransformBeforeLayout();
17020
+ const start = applyToPoint12(transform, { x: props.x1, y: props.y1 });
17021
+ const end = applyToPoint12(transform, { x: props.x2, y: props.y2 });
17022
+ const pcb_component_id = this.parent?.pcb_component_id ?? this.getPrimitiveContainer()?.pcb_component_id ?? void 0;
17023
+ const pcb_note_line = db.pcb_note_line.insert({
17024
+ pcb_component_id,
17025
+ subcircuit_id: subcircuit?.subcircuit_id ?? void 0,
17026
+ pcb_group_id: group?.pcb_group_id ?? void 0,
17027
+ x1: start.x,
17028
+ y1: start.y,
17029
+ x2: end.x,
17030
+ y2: end.y,
17031
+ stroke_width: props.strokeWidth ?? 0.1,
17032
+ color: props.color,
17033
+ is_dashed: props.isDashed
17070
17034
  });
17035
+ this.pcb_note_line_id = pcb_note_line.pcb_note_line_id;
17071
17036
  }
17072
- if (sourceElm.source_group_id && groupsMap?.has(sourceElm.source_group_id)) {
17073
- const group = groupsMap.get(sourceElm.source_group_id);
17074
- group.add(diode);
17075
- } else {
17076
- subcircuit.add(diode);
17037
+ getPcbSize() {
17038
+ const { _parsedProps: props } = this;
17039
+ return {
17040
+ width: Math.abs(props.x2 - props.x1),
17041
+ height: Math.abs(props.y2 - props.y1)
17042
+ };
17077
17043
  }
17078
- }
17044
+ };
17079
17045
 
17080
- // lib/components/primitive-components/Group/Subcircuit/inflators/inflateSourceTrace.ts
17081
- var getSelectorPath = (component, db) => {
17082
- const path_parts = [];
17083
- let currentGroupId = component.source_group_id;
17084
- while (currentGroupId) {
17085
- const group = db.source_group.get(currentGroupId);
17086
- if (!group) break;
17087
- path_parts.unshift(`.${group.name}`);
17088
- currentGroupId = group.parent_source_group_id;
17046
+ // lib/components/primitive-components/PcbNoteRect.ts
17047
+ import { pcbNoteRectProps } from "@tscircuit/props";
17048
+ import { applyToPoint as applyToPoint13 } from "transformation-matrix";
17049
+ var PcbNoteRect = class extends PrimitiveComponent2 {
17050
+ pcb_note_rect_id = null;
17051
+ isPcbPrimitive = true;
17052
+ get config() {
17053
+ return {
17054
+ componentName: "PcbNoteRect",
17055
+ zodProps: pcbNoteRectProps
17056
+ };
17089
17057
  }
17090
- path_parts.push(`.${component.name}`);
17091
- return path_parts.join(" > ");
17092
- };
17093
- function inflateSourceTrace(sourceTrace, inflatorContext) {
17094
- const { injectionDb, subcircuit } = inflatorContext;
17095
- const connectedSelectors = [];
17096
- for (const sourcePortId of sourceTrace.connected_source_port_ids) {
17097
- const sourcePort = injectionDb.source_port.get(sourcePortId);
17098
- if (!sourcePort) continue;
17099
- let selector;
17100
- if (sourcePort.source_component_id) {
17101
- const sourceComponent = injectionDb.source_component.get(
17102
- sourcePort.source_component_id
17103
- );
17104
- if (sourceComponent) {
17105
- const path = getSelectorPath(
17106
- {
17107
- name: sourceComponent.name,
17108
- source_group_id: sourceComponent.source_group_id
17109
- },
17110
- injectionDb
17111
- );
17112
- selector = `${path} > .${sourcePort.name}`;
17113
- }
17114
- } else {
17115
- selector = `.${sourcePort.name}`;
17116
- }
17117
- if (selector) {
17118
- connectedSelectors.push(selector);
17119
- }
17058
+ doInitialPcbPrimitiveRender() {
17059
+ if (this.root?.pcbDisabled) return;
17060
+ const { db } = this.root;
17061
+ const { _parsedProps: props } = this;
17062
+ const transform = this._computePcbGlobalTransformBeforeLayout();
17063
+ const center = applyToPoint13(transform, { x: 0, y: 0 });
17064
+ const subcircuit = this.getSubcircuit();
17065
+ const group = this.getGroup();
17066
+ const pcb_component_id = this.parent?.pcb_component_id ?? this.getPrimitiveContainer()?.pcb_component_id ?? void 0;
17067
+ const pcb_note_rect = db.pcb_note_rect.insert({
17068
+ pcb_component_id,
17069
+ subcircuit_id: subcircuit?.subcircuit_id ?? void 0,
17070
+ pcb_group_id: group?.pcb_group_id ?? void 0,
17071
+ center,
17072
+ width: props.width,
17073
+ height: props.height,
17074
+ stroke_width: props.strokeWidth ?? 0.1,
17075
+ is_filled: props.isFilled ?? false,
17076
+ has_stroke: props.hasStroke ?? true,
17077
+ is_stroke_dashed: props.isStrokeDashed ?? false,
17078
+ color: props.color,
17079
+ corner_radius: props.cornerRadius ?? void 0
17080
+ });
17081
+ this.pcb_note_rect_id = pcb_note_rect.pcb_note_rect_id;
17120
17082
  }
17121
- for (const sourceNetId of sourceTrace.connected_source_net_ids) {
17122
- const sourceNet = injectionDb.source_net.get(sourceNetId);
17123
- if (sourceNet) {
17124
- connectedSelectors.push(`net.${sourceNet.name}`);
17125
- }
17083
+ getPcbSize() {
17084
+ const { _parsedProps: props } = this;
17085
+ const width = typeof props.width === "string" ? parseFloat(props.width) : props.width;
17086
+ const height = typeof props.height === "string" ? parseFloat(props.height) : props.height;
17087
+ return { width, height };
17126
17088
  }
17127
- if (connectedSelectors.length < 2) return;
17128
- const trace = new Trace3({
17129
- path: connectedSelectors
17130
- });
17131
- trace.source_trace_id = sourceTrace.source_trace_id;
17132
- subcircuit.add(trace);
17133
- }
17089
+ };
17134
17090
 
17135
- // lib/components/normal-components/Transistor.ts
17136
- import { transistorProps } from "@tscircuit/props";
17137
- var Transistor = class extends NormalComponent3 {
17091
+ // lib/components/primitive-components/PcbNoteText.ts
17092
+ import { pcbNoteTextProps } from "@tscircuit/props";
17093
+ import { applyToPoint as applyToPoint14 } from "transformation-matrix";
17094
+ var PcbNoteText = class extends PrimitiveComponent2 {
17095
+ pcb_note_text_id = null;
17096
+ isPcbPrimitive = true;
17138
17097
  get config() {
17139
- const baseSymbolName = this.props.type === "npn" ? "npn_bipolar_transistor" : "pnp_bipolar_transistor";
17140
17098
  return {
17141
- componentName: "Transistor",
17142
- schematicSymbolName: this.props.symbolName ?? baseSymbolName,
17143
- zodProps: transistorProps,
17144
- sourceFtype: "simple_transistor",
17145
- shouldRenderAsSchematicBox: false
17099
+ componentName: "PcbNoteText",
17100
+ zodProps: pcbNoteTextProps
17146
17101
  };
17147
17102
  }
17148
- initPorts() {
17149
- const pinAliases = {
17150
- pin1: ["collector", "c"],
17151
- pin2: ["emitter", "e"],
17152
- pin3: ["base", "b"]
17153
- };
17154
- super.initPorts({
17155
- pinCount: 3,
17156
- additionalAliases: pinAliases
17103
+ doInitialPcbPrimitiveRender() {
17104
+ if (this.root?.pcbDisabled) return;
17105
+ const { db } = this.root;
17106
+ const { _parsedProps: props } = this;
17107
+ const transform = this._computePcbGlobalTransformBeforeLayout();
17108
+ const anchorPosition = applyToPoint14(transform, { x: 0, y: 0 });
17109
+ const subcircuit = this.getSubcircuit();
17110
+ const group = this.getGroup();
17111
+ const pcb_component_id = this.parent?.pcb_component_id ?? this.getPrimitiveContainer()?.pcb_component_id ?? void 0;
17112
+ const pcb_note_text = db.pcb_note_text.insert({
17113
+ pcb_component_id,
17114
+ subcircuit_id: subcircuit?.subcircuit_id ?? void 0,
17115
+ pcb_group_id: group?.pcb_group_id ?? void 0,
17116
+ font: props.font ?? "tscircuit2024",
17117
+ font_size: props.fontSize ?? 1,
17118
+ text: props.text,
17119
+ anchor_position: anchorPosition,
17120
+ anchor_alignment: props.anchorAlignment ?? "center",
17121
+ color: props.color
17157
17122
  });
17123
+ this.pcb_note_text_id = pcb_note_text.pcb_note_text_id;
17158
17124
  }
17159
- emitter = this.portMap.pin1;
17160
- collector = this.portMap.pin2;
17161
- base = this.portMap.pin3;
17162
- doInitialCreateNetsFromProps() {
17163
- this._createNetsFromProps([...this._getNetsFromConnectionsProp()]);
17125
+ getPcbSize() {
17126
+ const { _parsedProps: props } = this;
17127
+ const fontSize = typeof props.fontSize === "string" ? parseFloat(props.fontSize) : props.fontSize ?? 1;
17128
+ const charWidth = fontSize * 0.6;
17129
+ const width = props.text.length * charWidth;
17130
+ const height = fontSize;
17131
+ return { width, height };
17164
17132
  }
17165
- doInitialCreateTracesFromProps() {
17166
- this._createTracesFromConnectionsProp();
17133
+ };
17134
+
17135
+ // lib/components/primitive-components/PcbNotePath.ts
17136
+ import { pcbNotePathProps } from "@tscircuit/props";
17137
+ import { applyToPoint as applyToPoint15 } from "transformation-matrix";
17138
+ var PcbNotePath = class extends PrimitiveComponent2 {
17139
+ pcb_note_path_id = null;
17140
+ isPcbPrimitive = true;
17141
+ get config() {
17142
+ return {
17143
+ componentName: "PcbNotePath",
17144
+ zodProps: pcbNotePathProps
17145
+ };
17167
17146
  }
17168
- doInitialSourceRender() {
17147
+ doInitialPcbPrimitiveRender() {
17148
+ if (this.root?.pcbDisabled) return;
17169
17149
  const { db } = this.root;
17170
17150
  const { _parsedProps: props } = this;
17171
- const source_component = db.source_component.insert({
17172
- ftype: "simple_transistor",
17173
- name: this.name,
17174
- transistor_type: props.type
17151
+ const transform = this._computePcbGlobalTransformBeforeLayout();
17152
+ const subcircuit = this.getSubcircuit();
17153
+ const group = this.getGroup();
17154
+ const pcb_component_id = this.parent?.pcb_component_id ?? this.getPrimitiveContainer()?.pcb_component_id ?? void 0;
17155
+ const transformedRoute = props.route.map((point) => {
17156
+ const { x, y, ...rest } = point;
17157
+ const numericX = typeof x === "string" ? parseFloat(x) : x;
17158
+ const numericY = typeof y === "string" ? parseFloat(y) : y;
17159
+ const transformed = applyToPoint15(transform, { x: numericX, y: numericY });
17160
+ return { ...rest, x: transformed.x, y: transformed.y };
17175
17161
  });
17176
- this.source_component_id = source_component.source_component_id;
17162
+ const pcb_note_path = db.pcb_note_path.insert({
17163
+ pcb_component_id,
17164
+ subcircuit_id: subcircuit?.subcircuit_id ?? void 0,
17165
+ pcb_group_id: group?.pcb_group_id ?? void 0,
17166
+ route: transformedRoute,
17167
+ stroke_width: props.strokeWidth ?? 0.1,
17168
+ color: props.color
17169
+ });
17170
+ this.pcb_note_path_id = pcb_note_path.pcb_note_path_id;
17171
+ }
17172
+ getPcbSize() {
17173
+ const { _parsedProps: props } = this;
17174
+ if (props.route.length === 0) return { width: 0, height: 0 };
17175
+ const xs = props.route.map(
17176
+ (point) => typeof point.x === "string" ? parseFloat(point.x) : point.x
17177
+ );
17178
+ const ys = props.route.map(
17179
+ (point) => typeof point.y === "string" ? parseFloat(point.y) : point.y
17180
+ );
17181
+ const minX = Math.min(...xs);
17182
+ const maxX = Math.max(...xs);
17183
+ const minY = Math.min(...ys);
17184
+ const maxY = Math.max(...ys);
17185
+ return { width: maxX - minX, height: maxY - minY };
17177
17186
  }
17178
17187
  };
17179
17188
 
17180
- // lib/components/primitive-components/Group/Subcircuit/inflators/inflateSourceTransistor.ts
17181
- function inflateSourceTransistor(sourceElm, inflatorContext) {
17182
- const { injectionDb, subcircuit, groupsMap } = inflatorContext;
17183
- const pcbElm = injectionDb.pcb_component.getWhere({
17184
- source_component_id: sourceElm.source_component_id
17185
- });
17186
- const cadElm = injectionDb.cad_component.getWhere({
17187
- source_component_id: sourceElm.source_component_id
17188
- });
17189
- const transistor = new Transistor({
17190
- name: sourceElm.name,
17191
- type: sourceElm.transistor_type,
17192
- layer: pcbElm?.layer,
17193
- pcbX: pcbElm?.center?.x,
17194
- pcbY: pcbElm?.center?.y,
17195
- pcbRotation: pcbElm?.rotation,
17196
- doNotPlace: pcbElm?.do_not_place,
17197
- obstructsWithinBounds: pcbElm?.obstructs_within_bounds
17198
- });
17199
- if (pcbElm) {
17200
- inflatePcbComponent(pcbElm, {
17201
- ...inflatorContext,
17202
- normalComponent: transistor
17189
+ // lib/components/primitive-components/PcbNoteDimension.ts
17190
+ import { pcbNoteDimensionProps } from "@tscircuit/props";
17191
+ import { applyToPoint as applyToPoint16 } from "transformation-matrix";
17192
+ var PcbNoteDimension = class extends PrimitiveComponent2 {
17193
+ pcb_note_dimension_id = null;
17194
+ isPcbPrimitive = true;
17195
+ get config() {
17196
+ return {
17197
+ componentName: "PcbNoteDimension",
17198
+ zodProps: pcbNoteDimensionProps
17199
+ };
17200
+ }
17201
+ _resolvePoint(input, transform) {
17202
+ if (typeof input === "string") {
17203
+ const target = this.getSubcircuit().selectOne(
17204
+ `.${input}`
17205
+ );
17206
+ if (!target) {
17207
+ this.renderError(`PcbNoteDimension could not find selector "${input}"`);
17208
+ return applyToPoint16(transform, { x: 0, y: 0 });
17209
+ }
17210
+ return target._getGlobalPcbPositionBeforeLayout();
17211
+ }
17212
+ const numericX = typeof input.x === "string" ? parseFloat(input.x) : input.x;
17213
+ const numericY = typeof input.y === "string" ? parseFloat(input.y) : input.y;
17214
+ return applyToPoint16(transform, { x: numericX, y: numericY });
17215
+ }
17216
+ doInitialPcbPrimitiveRender() {
17217
+ if (this.root?.pcbDisabled) return;
17218
+ const { db } = this.root;
17219
+ const { _parsedProps: props } = this;
17220
+ const transform = this._computePcbGlobalTransformBeforeLayout();
17221
+ const from = this._resolvePoint(props.from, transform);
17222
+ const to = this._resolvePoint(props.to, transform);
17223
+ const subcircuit = this.getSubcircuit();
17224
+ const group = this.getGroup();
17225
+ const pcb_component_id = this.parent?.pcb_component_id ?? this.getPrimitiveContainer()?.pcb_component_id ?? void 0;
17226
+ const text = props.text ?? this._formatDistanceText({ from, to, units: props.units ?? "mm" });
17227
+ const pcb_note_dimension = db.pcb_note_dimension.insert({
17228
+ pcb_component_id,
17229
+ subcircuit_id: subcircuit?.subcircuit_id ?? void 0,
17230
+ pcb_group_id: group?.pcb_group_id ?? void 0,
17231
+ from,
17232
+ to,
17233
+ text,
17234
+ font: props.font ?? "tscircuit2024",
17235
+ font_size: props.fontSize ?? 1,
17236
+ color: props.color,
17237
+ arrow_size: props.arrowSize ?? 1
17203
17238
  });
17239
+ this.pcb_note_dimension_id = pcb_note_dimension.pcb_note_dimension_id;
17204
17240
  }
17205
- if (sourceElm.source_group_id && groupsMap?.has(sourceElm.source_group_id)) {
17206
- const group = groupsMap.get(sourceElm.source_group_id);
17207
- group.add(transistor);
17208
- } else {
17209
- subcircuit.add(transistor);
17241
+ getPcbSize() {
17242
+ const transform = this._computePcbGlobalTransformBeforeLayout();
17243
+ const from = this._resolvePoint(this._parsedProps.from, transform);
17244
+ const to = this._resolvePoint(this._parsedProps.to, transform);
17245
+ return {
17246
+ width: Math.abs(to.x - from.x),
17247
+ height: Math.abs(to.y - from.y)
17248
+ };
17210
17249
  }
17211
- }
17250
+ _formatDistanceText({
17251
+ from,
17252
+ to,
17253
+ units
17254
+ }) {
17255
+ const dx = to.x - from.x;
17256
+ const dy = to.y - from.y;
17257
+ const distanceInMillimeters = Math.sqrt(dx * dx + dy * dy);
17258
+ const distanceInUnits = units === "in" ? distanceInMillimeters / 25.4 : distanceInMillimeters;
17259
+ const roundedDistance = Math.round(distanceInUnits);
17260
+ const isWholeNumber = Math.abs(distanceInUnits - roundedDistance) < 1e-9;
17261
+ if (isWholeNumber) {
17262
+ return `${roundedDistance}${units}`;
17263
+ }
17264
+ const decimalPlaces = units === "in" ? 3 : 2;
17265
+ const valueText = units === "in" ? Number(distanceInUnits.toFixed(decimalPlaces)).toString() : distanceInUnits.toFixed(decimalPlaces);
17266
+ return `${valueText}${units}`;
17267
+ }
17268
+ };
17212
17269
 
17213
17270
  // lib/components/primitive-components/Group/Subcircuit/Subcircuit.ts
17271
+ import "@tscircuit/props";
17214
17272
  var Subcircuit = class extends Group6 {
17215
17273
  constructor(props) {
17216
17274
  super({
@@ -17233,57 +17291,8 @@ var Subcircuit = class extends Group6 {
17233
17291
  * - Add components to groups in the appropriate hierarchy
17234
17292
  */
17235
17293
  doInitialInflateSubcircuitCircuitJson() {
17236
- const { circuitJson: injectionCircuitJson, children } = this._parsedProps;
17237
- if (!injectionCircuitJson) return;
17238
- const injectionDb = cju(injectionCircuitJson);
17239
- if (injectionCircuitJson && children?.length > 0) {
17240
- throw new Error("Subcircuit cannot have both circuitJson and children");
17241
- }
17242
- const groupsMap = /* @__PURE__ */ new Map();
17243
- const inflationCtx = {
17244
- injectionDb,
17245
- subcircuit: this,
17246
- groupsMap
17247
- };
17248
- const sourceGroups = injectionDb.source_group.list();
17249
- for (const sourceGroup of sourceGroups) {
17250
- inflateSourceGroup(sourceGroup, inflationCtx);
17251
- }
17252
- const sourceComponents = injectionDb.source_component.list();
17253
- for (const sourceComponent of sourceComponents) {
17254
- switch (sourceComponent.ftype) {
17255
- case "simple_resistor":
17256
- inflateSourceResistor(sourceComponent, inflationCtx);
17257
- break;
17258
- case "simple_capacitor":
17259
- inflateSourceCapacitor(sourceComponent, inflationCtx);
17260
- break;
17261
- case "simple_inductor":
17262
- inflateSourceInductor(sourceComponent, inflationCtx);
17263
- break;
17264
- case "simple_diode":
17265
- inflateSourceDiode(sourceComponent, inflationCtx);
17266
- break;
17267
- case "simple_chip":
17268
- inflateSourceChip(sourceComponent, inflationCtx);
17269
- break;
17270
- case "simple_transistor":
17271
- inflateSourceTransistor(sourceComponent, inflationCtx);
17272
- break;
17273
- default:
17274
- throw new Error(
17275
- `No inflator implemented for source component ftype: "${sourceComponent.ftype}"`
17276
- );
17277
- }
17278
- }
17279
- const sourcePorts = injectionDb.source_port.list();
17280
- for (const sourcePort of sourcePorts) {
17281
- inflateSourcePort(sourcePort, inflationCtx);
17282
- }
17283
- const sourceTraces = injectionDb.source_trace.list();
17284
- for (const sourceTrace of sourceTraces) {
17285
- inflateSourceTrace(sourceTrace, inflationCtx);
17286
- }
17294
+ const { circuitJson, children } = this._parsedProps;
17295
+ inflateCircuitJson(this, circuitJson, children);
17287
17296
  }
17288
17297
  };
17289
17298
 
@@ -19193,7 +19202,7 @@ import { identity as identity6 } from "transformation-matrix";
19193
19202
  var package_default = {
19194
19203
  name: "@tscircuit/core",
19195
19204
  type: "module",
19196
- version: "0.0.891",
19205
+ version: "0.0.892",
19197
19206
  types: "dist/index.d.ts",
19198
19207
  main: "dist/index.js",
19199
19208
  module: "dist/index.js",