@tscircuit/core 0.0.1858 → 0.0.1859

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -18,6 +18,7 @@ import { FanoutSolver } from '@tscircuit/fanout-solver';
18
18
  import { ImplicitCopperPourPipelineSolver } from '@tscircuit/implicit-copper-pour-solver/lib/index';
19
19
  import { LayoutPipelineSolver } from '@tscircuit/matchpack';
20
20
  import { SchematicTracePipelineSolver } from '@tscircuit/schematic-trace-solver';
21
+ import { ViaStitchSolver } from '@tscircuit/via-stitch-solver';
21
22
  import { PackSolver2 } from 'calculate-packing';
22
23
  import { Box, Bounds } from '@tscircuit/math-utils';
23
24
  import { ConnectivityMap } from 'circuit-json-to-connectivity-map';
@@ -42,6 +43,7 @@ declare const SOLVERS: {
42
43
  FanoutSolver: typeof FanoutSolver;
43
44
  ImplicitCopperPourPipelineSolver: typeof ImplicitCopperPourPipelineSolver;
44
45
  SchematicTracePipelineSolver: typeof SchematicTracePipelineSolver;
46
+ ViaStitchSolver: typeof ViaStitchSolver;
45
47
  };
46
48
  type SolverName = keyof typeof SOLVERS;
47
49
 
@@ -358,9 +360,9 @@ interface IIsolatedCircuit {
358
360
  interface IRootCircuit extends IIsolatedCircuit {
359
361
  }
360
362
 
361
- declare const orderedRenderPhases: readonly ["ReactSubtreesRender", "RenderIsolatedSubcircuits", "InflateSubcircuitCircuitJson", "SourceNameDuplicateComponentRemoval", "PcbFootprintStringRender", "FetchPartFootprint", "ResolveFootprintPinLabels", "InitializePortsFromChildren", "CreateNetsFromProps", "AssignFallbackProps", "CreateTracesFromProps", "CreateTracesFromNetLabels", "CreateTraceHintsFromProps", "CreateAutoplacedBreakoutPoints", "SourceGroupRender", "AssignNameToUnnamedComponents", "SourceRender", "CheckRefDesConvention", "SourceComponentPropertyValidation", "SourceParentAttachment", "PortMatching", "OptimizeSelectorCache", "SourceTraceRender", "SourceAddConnectivityMapKey", "SourceDesignRuleChecks", "SimulationRender", "SchematicComponentRender", "SchematicPortRender", "SymbolContainerRender", "SchematicPrimitiveRender", "SchematicSymbolResize", "SchematicComponentSizeCalculation", "SchematicLayout", "SchematicSectionRender", "SchematicTraceRender", "SchematicSheetRender", "SchematicReplaceNetLabelsWithSymbols", "SchematicLabelNetsWithConflictingNames", "PanelBoardLayout", "ValidatePcbCoordinates", "PcbComponentRender", "PcbPrimitiveRender", "PcbFootprintLayout", "PcbPortRender", "PcbPortAttachment", "PcbComponentSizeCalculation", "PcbComponentAnchorAlignment", "PcbCalcPlacementResolution", "PcbLayout", "PcbBoardAutoSize", "PanelLayout", "PcbAutoplaceBreakoutPoints", "PcbTraceHintRender", "PcbManualTraceRender", "PcbPlacementDesignRuleChecks", "PcbTraceRender", "PcbRouteNetIslands", "PcbImplicitCopperPourRender", "PcbCopperPourRender", "PcbDesignRuleChecks", "SilkscreenOverlapAdjustment", "CadModelRender", "PartsEngineRender", "PartOrientationAnalysis", "SupplierFootprintMismatchWarning", "SimulationSpiceEngineRender"];
363
+ declare const orderedRenderPhases: readonly ["ReactSubtreesRender", "RenderIsolatedSubcircuits", "InflateSubcircuitCircuitJson", "SourceNameDuplicateComponentRemoval", "PcbFootprintStringRender", "FetchPartFootprint", "ResolveFootprintPinLabels", "InitializePortsFromChildren", "CreateNetsFromProps", "AssignFallbackProps", "CreateTracesFromProps", "CreateTracesFromNetLabels", "CreateTraceHintsFromProps", "CreateAutoplacedBreakoutPoints", "SourceGroupRender", "AssignNameToUnnamedComponents", "SourceRender", "CheckRefDesConvention", "SourceComponentPropertyValidation", "SourceParentAttachment", "PortMatching", "OptimizeSelectorCache", "SourceTraceRender", "SourceAddConnectivityMapKey", "SourceDesignRuleChecks", "SimulationRender", "SchematicComponentRender", "SchematicPortRender", "SymbolContainerRender", "SchematicPrimitiveRender", "SchematicSymbolResize", "SchematicComponentSizeCalculation", "SchematicLayout", "SchematicSectionRender", "SchematicTraceRender", "SchematicSheetRender", "SchematicReplaceNetLabelsWithSymbols", "SchematicLabelNetsWithConflictingNames", "PanelBoardLayout", "ValidatePcbCoordinates", "PcbComponentRender", "PcbPrimitiveRender", "PcbFootprintLayout", "PcbPortRender", "PcbPortAttachment", "PcbComponentSizeCalculation", "PcbComponentAnchorAlignment", "PcbCalcPlacementResolution", "PcbLayout", "PcbBoardAutoSize", "PanelLayout", "PcbAutoplaceBreakoutPoints", "PcbTraceHintRender", "PcbManualTraceRender", "PcbPlacementDesignRuleChecks", "PcbTraceRender", "PcbRouteNetIslands", "PcbImplicitCopperPourRender", "PcbCopperPourRender", "PcbViaStitchRender", "PcbDesignRuleChecks", "SilkscreenOverlapAdjustment", "CadModelRender", "PartsEngineRender", "PartOrientationAnalysis", "SupplierFootprintMismatchWarning", "SimulationSpiceEngineRender"];
362
364
  type RenderPhase = (typeof orderedRenderPhases)[number];
363
- declare const renderPhaseIndexMap: Map<"ReactSubtreesRender" | "RenderIsolatedSubcircuits" | "InflateSubcircuitCircuitJson" | "SourceNameDuplicateComponentRemoval" | "PcbFootprintStringRender" | "FetchPartFootprint" | "ResolveFootprintPinLabels" | "InitializePortsFromChildren" | "CreateNetsFromProps" | "AssignFallbackProps" | "CreateTracesFromProps" | "CreateTracesFromNetLabels" | "CreateTraceHintsFromProps" | "CreateAutoplacedBreakoutPoints" | "SourceGroupRender" | "AssignNameToUnnamedComponents" | "SourceRender" | "CheckRefDesConvention" | "SourceComponentPropertyValidation" | "SourceParentAttachment" | "PortMatching" | "OptimizeSelectorCache" | "SourceTraceRender" | "SourceAddConnectivityMapKey" | "SourceDesignRuleChecks" | "SimulationRender" | "SchematicComponentRender" | "SchematicPortRender" | "SymbolContainerRender" | "SchematicPrimitiveRender" | "SchematicSymbolResize" | "SchematicComponentSizeCalculation" | "SchematicLayout" | "SchematicSectionRender" | "SchematicTraceRender" | "SchematicSheetRender" | "SchematicReplaceNetLabelsWithSymbols" | "SchematicLabelNetsWithConflictingNames" | "PanelBoardLayout" | "ValidatePcbCoordinates" | "PcbComponentRender" | "PcbPrimitiveRender" | "PcbFootprintLayout" | "PcbPortRender" | "PcbPortAttachment" | "PcbComponentSizeCalculation" | "PcbComponentAnchorAlignment" | "PcbCalcPlacementResolution" | "PcbLayout" | "PcbBoardAutoSize" | "PanelLayout" | "PcbAutoplaceBreakoutPoints" | "PcbTraceHintRender" | "PcbManualTraceRender" | "PcbPlacementDesignRuleChecks" | "PcbTraceRender" | "PcbRouteNetIslands" | "PcbImplicitCopperPourRender" | "PcbCopperPourRender" | "PcbDesignRuleChecks" | "SilkscreenOverlapAdjustment" | "CadModelRender" | "PartsEngineRender" | "PartOrientationAnalysis" | "SupplierFootprintMismatchWarning" | "SimulationSpiceEngineRender", number>;
365
+ declare const renderPhaseIndexMap: Map<"ReactSubtreesRender" | "RenderIsolatedSubcircuits" | "InflateSubcircuitCircuitJson" | "SourceNameDuplicateComponentRemoval" | "PcbFootprintStringRender" | "FetchPartFootprint" | "ResolveFootprintPinLabels" | "InitializePortsFromChildren" | "CreateNetsFromProps" | "AssignFallbackProps" | "CreateTracesFromProps" | "CreateTracesFromNetLabels" | "CreateTraceHintsFromProps" | "CreateAutoplacedBreakoutPoints" | "SourceGroupRender" | "AssignNameToUnnamedComponents" | "SourceRender" | "CheckRefDesConvention" | "SourceComponentPropertyValidation" | "SourceParentAttachment" | "PortMatching" | "OptimizeSelectorCache" | "SourceTraceRender" | "SourceAddConnectivityMapKey" | "SourceDesignRuleChecks" | "SimulationRender" | "SchematicComponentRender" | "SchematicPortRender" | "SymbolContainerRender" | "SchematicPrimitiveRender" | "SchematicSymbolResize" | "SchematicComponentSizeCalculation" | "SchematicLayout" | "SchematicSectionRender" | "SchematicTraceRender" | "SchematicSheetRender" | "SchematicReplaceNetLabelsWithSymbols" | "SchematicLabelNetsWithConflictingNames" | "PanelBoardLayout" | "ValidatePcbCoordinates" | "PcbComponentRender" | "PcbPrimitiveRender" | "PcbFootprintLayout" | "PcbPortRender" | "PcbPortAttachment" | "PcbComponentSizeCalculation" | "PcbComponentAnchorAlignment" | "PcbCalcPlacementResolution" | "PcbLayout" | "PcbBoardAutoSize" | "PanelLayout" | "PcbAutoplaceBreakoutPoints" | "PcbTraceHintRender" | "PcbManualTraceRender" | "PcbPlacementDesignRuleChecks" | "PcbTraceRender" | "PcbRouteNetIslands" | "PcbImplicitCopperPourRender" | "PcbCopperPourRender" | "PcbViaStitchRender" | "PcbDesignRuleChecks" | "SilkscreenOverlapAdjustment" | "CadModelRender" | "PartsEngineRender" | "PartOrientationAnalysis" | "SupplierFootprintMismatchWarning" | "SimulationSpiceEngineRender", number>;
364
366
  type RenderPhaseFn<K extends RenderPhase = RenderPhase> = `doInitial${K}` | `update${K}` | `remove${K}`;
365
367
  type RenderPhaseStates = Record<RenderPhase, {
366
368
  initialized: boolean;
@@ -522,6 +524,8 @@ declare class IsolatedCircuit {
522
524
  pcbDisabled: boolean;
523
525
  pcbRoutingDisabled: boolean;
524
526
  _featureMspSchematicTraceRouting: boolean;
527
+ /** Experimental automatic via stitching; opt in before rendering. */
528
+ _featurePcbViaStitching: boolean;
525
529
  /**
526
530
  * The IsolatedCircuit name is usually set by the platform, it's not required but
527
531
  * if supplied can identify the circuit in certain effects, e.g. it is passed
@@ -107902,6 +107906,7 @@ declare class CopperPour extends PrimitiveComponent<typeof copperPourProps> {
107902
107906
  };
107903
107907
  doInitialCreateNetsFromProps(): void;
107904
107908
  doInitialPcbCopperPourRender(): void;
107909
+ doInitialPcbViaStitchRender(): void;
107905
107910
  }
107906
107911
 
107907
107912
  declare class CopperText extends PrimitiveComponent<typeof copperTextProps> {
package/dist/index.js CHANGED
@@ -452,6 +452,7 @@ var orderedRenderPhases = [
452
452
  "PcbRouteNetIslands",
453
453
  "PcbImplicitCopperPourRender",
454
454
  "PcbCopperPourRender",
455
+ "PcbViaStitchRender",
455
456
  "PcbDesignRuleChecks",
456
457
  "SilkscreenOverlapAdjustment",
457
458
  "CadModelRender",
@@ -513,6 +514,15 @@ var asyncPhaseDependencies = {
513
514
  "PcbTraceRender",
514
515
  "PcbRouteNetIslands"
515
516
  ],
517
+ PcbViaStitchRender: [
518
+ "PcbFootprintStringRender",
519
+ "FetchPartFootprint",
520
+ "PcbPlacementDesignRuleChecks",
521
+ "PcbTraceRender",
522
+ "PcbRouteNetIslands",
523
+ "PcbImplicitCopperPourRender",
524
+ "PcbCopperPourRender"
525
+ ],
516
526
  PcbPlacementDesignRuleChecks: [
517
527
  "PcbFootprintStringRender",
518
528
  "FetchPartFootprint"
@@ -529,7 +539,8 @@ var asyncPhaseDependencies = {
529
539
  "PcbPlacementDesignRuleChecks",
530
540
  "PcbTraceRender",
531
541
  "PcbImplicitCopperPourRender",
532
- "PcbCopperPourRender"
542
+ "PcbCopperPourRender",
543
+ "PcbViaStitchRender"
533
544
  ],
534
545
  SilkscreenOverlapAdjustment: [
535
546
  "PcbFootprintStringRender",
@@ -40819,6 +40830,480 @@ var ImplicitCopperPourPipelineSolver = class extends BasePipelineSolver {
40819
40830
  // lib/solvers.ts
40820
40831
  import { LayoutPipelineSolver } from "@tscircuit/matchpack";
40821
40832
  import { SchematicTracePipelineSolver } from "@tscircuit/schematic-trace-solver";
40833
+
40834
+ // node_modules/@tscircuit/via-stitch-solver/lib/solvers/ViaStitchSolver.ts
40835
+ import { BaseSolver as BaseSolver3 } from "@tscircuit/solver-utils";
40836
+
40837
+ // node_modules/@tscircuit/via-stitch-solver/lib/geometry/brep-point-containment.ts
40838
+ var POINT_EPSILON = 1e-8;
40839
+ var isPointOnSegment = (point6, start, end) => {
40840
+ const cross3 = (point6.y - start.y) * (end.x - start.x) - (point6.x - start.x) * (end.y - start.y);
40841
+ if (Math.abs(cross3) > POINT_EPSILON) return false;
40842
+ const dot = (point6.x - start.x) * (end.x - start.x) + (point6.y - start.y) * (end.y - start.y);
40843
+ if (dot < -POINT_EPSILON) return false;
40844
+ const squaredLength = (end.x - start.x) ** 2 + (end.y - start.y) ** 2;
40845
+ return dot <= squaredLength + POINT_EPSILON;
40846
+ };
40847
+ var isPointInRing = (point6, ring) => {
40848
+ let isInside = false;
40849
+ for (let currentIndex = 0, previousIndex = ring.vertices.length - 1; currentIndex < ring.vertices.length; previousIndex = currentIndex++) {
40850
+ const current = ring.vertices[currentIndex];
40851
+ const previous = ring.vertices[previousIndex];
40852
+ if (isPointOnSegment(point6, previous, current)) return true;
40853
+ const crossesRay = current.y > point6.y !== previous.y > point6.y && point6.x < (previous.x - current.x) * (point6.y - current.y) / (previous.y - current.y) + current.x;
40854
+ if (crossesRay) isInside = !isInside;
40855
+ }
40856
+ return isInside;
40857
+ };
40858
+ var isPointInShape = (point6, shape) => isPointInRing(point6, shape.outer_ring) && !shape.inner_rings.some((innerRing) => isPointInRing(point6, innerRing));
40859
+ var isPointInShapeUnion = (point6, shapes) => shapes.some((shape) => isPointInShape(point6, shape));
40860
+ var getShapeUnionBounds = (shapes) => {
40861
+ const vertices = shapes.flatMap((shape) => shape.outer_ring.vertices);
40862
+ if (vertices.length === 0) return void 0;
40863
+ return {
40864
+ minX: Math.min(...vertices.map((vertex) => vertex.x)),
40865
+ maxX: Math.max(...vertices.map((vertex) => vertex.x)),
40866
+ minY: Math.min(...vertices.map((vertex) => vertex.y)),
40867
+ maxY: Math.max(...vertices.map((vertex) => vertex.y))
40868
+ };
40869
+ };
40870
+ var isViaAnnulusInsideShapeUnion = ({
40871
+ center,
40872
+ radius,
40873
+ shapes
40874
+ }) => {
40875
+ const samplePoints = [center];
40876
+ for (let sampleIndex = 0; sampleIndex < 32; sampleIndex++) {
40877
+ const angle = sampleIndex / 32 * Math.PI * 2;
40878
+ samplePoints.push({
40879
+ x: center.x + Math.cos(angle) * radius,
40880
+ y: center.y + Math.sin(angle) * radius
40881
+ });
40882
+ }
40883
+ return samplePoints.every(
40884
+ (samplePoint) => isPointInShapeUnion(samplePoint, shapes)
40885
+ );
40886
+ };
40887
+
40888
+ // node_modules/@tscircuit/via-stitch-solver/lib/geometry/circuit-element-obstacles.ts
40889
+ var layerMatches = (layer, layers) => layers.some((candidateLayer) => String(candidateLayer) === String(layer));
40890
+ var componentToObstacle = (component) => {
40891
+ if (component.do_not_place || !component.obstructs_within_bounds) {
40892
+ return void 0;
40893
+ }
40894
+ return {
40895
+ kind: "rect",
40896
+ center: component.center,
40897
+ width: component.width,
40898
+ height: component.height,
40899
+ ccwRotation: component.rotation
40900
+ };
40901
+ };
40902
+ var smtPadToObstacle = (smtPad) => {
40903
+ if (smtPad.shape === "circle") {
40904
+ return {
40905
+ kind: "circle",
40906
+ center: { x: smtPad.x, y: smtPad.y },
40907
+ radius: smtPad.radius
40908
+ };
40909
+ }
40910
+ if (smtPad.shape === "polygon") {
40911
+ return { kind: "polygon", points: smtPad.points };
40912
+ }
40913
+ return {
40914
+ kind: "rect",
40915
+ center: { x: smtPad.x, y: smtPad.y },
40916
+ width: smtPad.width,
40917
+ height: smtPad.height,
40918
+ ccwRotation: smtPad.shape === "rotated_rect" || smtPad.shape === "rotated_pill" ? smtPad.ccw_rotation : 0
40919
+ };
40920
+ };
40921
+ var platedHoleToObstacle = (platedHole) => {
40922
+ if (platedHole.shape === "circle") {
40923
+ return {
40924
+ kind: "circle",
40925
+ center: { x: platedHole.x, y: platedHole.y },
40926
+ radius: platedHole.outer_diameter / 2
40927
+ };
40928
+ }
40929
+ if ("outer_width" in platedHole) {
40930
+ return {
40931
+ kind: "rect",
40932
+ center: { x: platedHole.x, y: platedHole.y },
40933
+ width: platedHole.outer_width,
40934
+ height: platedHole.outer_height,
40935
+ ccwRotation: platedHole.ccw_rotation
40936
+ };
40937
+ }
40938
+ if (platedHole.shape === "hole_with_polygon_pad") {
40939
+ const rotationRadians = (platedHole.ccw_rotation ?? 0) * Math.PI / 180;
40940
+ const cosine = Math.cos(rotationRadians);
40941
+ const sine = Math.sin(rotationRadians);
40942
+ return {
40943
+ kind: "polygon",
40944
+ points: platedHole.pad_outline.map((point6) => ({
40945
+ x: platedHole.x + point6.x * cosine - point6.y * sine,
40946
+ y: platedHole.y + point6.x * sine + point6.y * cosine
40947
+ }))
40948
+ };
40949
+ }
40950
+ return {
40951
+ kind: "rect",
40952
+ center: { x: platedHole.x, y: platedHole.y },
40953
+ width: platedHole.rect_pad_width,
40954
+ height: platedHole.rect_pad_height,
40955
+ ccwRotation: "rect_ccw_rotation" in platedHole ? platedHole.rect_ccw_rotation ?? 0 : 0
40956
+ };
40957
+ };
40958
+ var holeToObstacle = (hole) => {
40959
+ if ("hole_diameter" in hole) {
40960
+ if (hole.hole_shape === "circle") {
40961
+ return {
40962
+ kind: "circle",
40963
+ center: { x: hole.x, y: hole.y },
40964
+ radius: hole.hole_diameter / 2
40965
+ };
40966
+ }
40967
+ return {
40968
+ kind: "rect",
40969
+ center: { x: hole.x, y: hole.y },
40970
+ width: hole.hole_diameter,
40971
+ height: hole.hole_diameter,
40972
+ ccwRotation: 0
40973
+ };
40974
+ }
40975
+ return {
40976
+ kind: "rect",
40977
+ center: { x: hole.x, y: hole.y },
40978
+ width: hole.hole_width,
40979
+ height: hole.hole_height,
40980
+ ccwRotation: hole.hole_shape === "rotated_pill" ? hole.ccw_rotation : 0
40981
+ };
40982
+ };
40983
+ var getDistanceToSegment = (point6, start, end) => {
40984
+ const segmentX = end.x - start.x;
40985
+ const segmentY = end.y - start.y;
40986
+ const squaredLength = segmentX ** 2 + segmentY ** 2;
40987
+ if (squaredLength === 0)
40988
+ return Math.hypot(point6.x - start.x, point6.y - start.y);
40989
+ const projection = Math.max(
40990
+ 0,
40991
+ Math.min(
40992
+ 1,
40993
+ ((point6.x - start.x) * segmentX + (point6.y - start.y) * segmentY) / squaredLength
40994
+ )
40995
+ );
40996
+ return Math.hypot(
40997
+ point6.x - (start.x + projection * segmentX),
40998
+ point6.y - (start.y + projection * segmentY)
40999
+ );
41000
+ };
41001
+ var isPointInPolygon = (point6, polygon) => {
41002
+ let isInside = false;
41003
+ for (let currentIndex = 0, previousIndex = polygon.length - 1; currentIndex < polygon.length; previousIndex = currentIndex++) {
41004
+ const current = polygon[currentIndex];
41005
+ const previous = polygon[previousIndex];
41006
+ const crossesRay = current.y > point6.y !== previous.y > point6.y && point6.x < (previous.x - current.x) * (point6.y - current.y) / (previous.y - current.y) + current.x;
41007
+ if (crossesRay) isInside = !isInside;
41008
+ }
41009
+ return isInside;
41010
+ };
41011
+ var doesCircleIntersectObstacle = (center, radius, obstacle) => {
41012
+ if (obstacle.kind === "circle") {
41013
+ return Math.hypot(center.x - obstacle.center.x, center.y - obstacle.center.y) < radius + obstacle.radius;
41014
+ }
41015
+ if (obstacle.kind === "polygon") {
41016
+ if (isPointInPolygon(center, obstacle.points)) return true;
41017
+ return obstacle.points.some(
41018
+ (point6, pointIndex) => Boolean(
41019
+ getDistanceToSegment(
41020
+ center,
41021
+ point6,
41022
+ obstacle.points[(pointIndex + 1) % obstacle.points.length]
41023
+ ) < radius
41024
+ )
41025
+ );
41026
+ }
41027
+ const rotationRadians = -obstacle.ccwRotation * Math.PI / 180;
41028
+ const deltaX = center.x - obstacle.center.x;
41029
+ const deltaY = center.y - obstacle.center.y;
41030
+ const localX = deltaX * Math.cos(rotationRadians) - deltaY * Math.sin(rotationRadians);
41031
+ const localY = deltaX * Math.sin(rotationRadians) + deltaY * Math.cos(rotationRadians);
41032
+ const outsideX = Math.max(Math.abs(localX) - obstacle.width / 2, 0);
41033
+ const outsideY = Math.max(Math.abs(localY) - obstacle.height / 2, 0);
41034
+ return Math.hypot(outsideX, outsideY) < radius;
41035
+ };
41036
+ var getStitchingObstacles = (circuitJson, layers) => circuitJson.flatMap((element) => {
41037
+ if (element.type === "pcb_component" && layerMatches(element.layer, layers)) {
41038
+ const obstacle = componentToObstacle(element);
41039
+ return obstacle ? [obstacle] : [];
41040
+ }
41041
+ if (element.type === "pcb_smtpad" && layerMatches(element.layer, layers)) {
41042
+ return [smtPadToObstacle(element)];
41043
+ }
41044
+ if (element.type === "pcb_plated_hole" && element.layers.some((layer) => layerMatches(layer, layers))) {
41045
+ return [platedHoleToObstacle(element)];
41046
+ }
41047
+ if (element.type === "pcb_hole") return [holeToObstacle(element)];
41048
+ return [];
41049
+ });
41050
+ var doesViaIntersectStitchingObstacle = ({
41051
+ center,
41052
+ radius,
41053
+ obstacles
41054
+ }) => obstacles.some(
41055
+ (obstacle) => doesCircleIntersectObstacle(center, radius, obstacle)
41056
+ );
41057
+
41058
+ // node_modules/@tscircuit/via-stitch-solver/lib/solvers/ViaStitchSolver.ts
41059
+ var resolveOptions = (options = {}) => {
41060
+ const resolvedOptions = {
41061
+ sourceNetIds: options.sourceNetIds ? new Set(options.sourceNetIds) : void 0,
41062
+ layers: options.layers ?? ["top", "bottom"],
41063
+ viaPitch: options.viaPitch ?? 1,
41064
+ viaHoleDiameter: options.viaHoleDiameter ?? 0.3,
41065
+ viaOuterDiameter: options.viaOuterDiameter ?? 0.6,
41066
+ pourEdgeClearance: options.pourEdgeClearance ?? 0.2,
41067
+ obstacleClearance: options.obstacleClearance ?? 0.2,
41068
+ minimumViaSeparation: options.minimumViaSeparation ?? Math.max(options.viaOuterDiameter ?? 0.6, 0.8),
41069
+ gridOrigin: options.gridOrigin ?? { x: 0, y: 0 },
41070
+ isTented: options.isTented ?? true
41071
+ };
41072
+ for (const [optionName, optionValue] of [
41073
+ ["viaPitch", resolvedOptions.viaPitch],
41074
+ ["viaHoleDiameter", resolvedOptions.viaHoleDiameter],
41075
+ ["viaOuterDiameter", resolvedOptions.viaOuterDiameter],
41076
+ ["minimumViaSeparation", resolvedOptions.minimumViaSeparation]
41077
+ ]) {
41078
+ if (!Number.isFinite(optionValue) || optionValue <= 0) {
41079
+ throw new Error(`${optionName} must be a finite number greater than zero`);
41080
+ }
41081
+ }
41082
+ if (!Number.isFinite(resolvedOptions.pourEdgeClearance) || resolvedOptions.pourEdgeClearance < 0) {
41083
+ throw new Error("pourEdgeClearance must be a finite non-negative number");
41084
+ }
41085
+ if (!Number.isFinite(resolvedOptions.obstacleClearance) || resolvedOptions.obstacleClearance < 0) {
41086
+ throw new Error("obstacleClearance must be a finite non-negative number");
41087
+ }
41088
+ if (!Number.isFinite(resolvedOptions.gridOrigin.x) || !Number.isFinite(resolvedOptions.gridOrigin.y)) {
41089
+ throw new Error("gridOrigin coordinates must be finite numbers");
41090
+ }
41091
+ if (resolvedOptions.viaHoleDiameter >= resolvedOptions.viaOuterDiameter) {
41092
+ throw new Error("viaHoleDiameter must be smaller than viaOuterDiameter");
41093
+ }
41094
+ if (String(resolvedOptions.layers[0]) === String(resolvedOptions.layers[1])) {
41095
+ throw new Error("layers must contain two distinct PCB layers");
41096
+ }
41097
+ return resolvedOptions;
41098
+ };
41099
+ var isBrepCopperPour = (element) => element.type === "pcb_copper_pour" && element.shape === "brep";
41100
+ var getCopperPourPairContexts = (input, options) => {
41101
+ const sourceNetsById = new Map(
41102
+ input.circuitJson.filter((element) => element.type === "source_net").map((sourceNet) => [sourceNet.source_net_id, sourceNet])
41103
+ );
41104
+ const poursBySourceNetId = /* @__PURE__ */ new Map();
41105
+ for (const element of input.circuitJson) {
41106
+ if (!isBrepCopperPour(element) || !element.source_net_id) continue;
41107
+ if (options.sourceNetIds && !options.sourceNetIds.has(element.source_net_id)) {
41108
+ continue;
41109
+ }
41110
+ const sourceNetPours = poursBySourceNetId.get(element.source_net_id) ?? [];
41111
+ sourceNetPours.push(element);
41112
+ poursBySourceNetId.set(element.source_net_id, sourceNetPours);
41113
+ }
41114
+ const [fromLayer, toLayer] = options.layers;
41115
+ const contexts = [];
41116
+ for (const [sourceNetId, sourceNetPours] of poursBySourceNetId) {
41117
+ const fromLayerPours = sourceNetPours.filter(
41118
+ (copperPour) => String(copperPour.layer) === String(fromLayer)
41119
+ );
41120
+ const toLayerPours = sourceNetPours.filter(
41121
+ (copperPour) => String(copperPour.layer) === String(toLayer)
41122
+ );
41123
+ if (fromLayerPours.length === 0 || toLayerPours.length === 0) continue;
41124
+ contexts.push({
41125
+ sourceNetId,
41126
+ sourceNet: sourceNetsById.get(sourceNetId),
41127
+ fromLayerPours,
41128
+ toLayerPours
41129
+ });
41130
+ }
41131
+ return contexts;
41132
+ };
41133
+ var getPcbTraceViaRadius = (routePoint, fallbackRadius) => {
41134
+ const routePointWithDiameter = routePoint;
41135
+ return (routePointWithDiameter.outer_diameter ?? fallbackRadius * 2) / 2;
41136
+ };
41137
+ var isTooCloseToOccupiedVia = ({
41138
+ center,
41139
+ radius,
41140
+ occupiedVias,
41141
+ minimumViaSeparation
41142
+ }) => occupiedVias.some(
41143
+ (occupiedVia) => Math.hypot(
41144
+ center.x - occupiedVia.center.x,
41145
+ center.y - occupiedVia.center.y
41146
+ ) < Math.max(minimumViaSeparation, radius + occupiedVia.radius)
41147
+ );
41148
+ var getGridCoordinates = ({
41149
+ minimum,
41150
+ maximum,
41151
+ origin,
41152
+ pitch
41153
+ }) => {
41154
+ const coordinates = [];
41155
+ const firstGridIndex = Math.ceil((minimum - origin) / pitch);
41156
+ const lastGridIndex = Math.floor((maximum - origin) / pitch);
41157
+ for (let gridIndex = firstGridIndex; gridIndex <= lastGridIndex; gridIndex++) {
41158
+ coordinates.push(origin + gridIndex * pitch);
41159
+ }
41160
+ return coordinates;
41161
+ };
41162
+ var ViaStitchSolver = class extends BaseSolver3 {
41163
+ constructor(input) {
41164
+ super();
41165
+ this.input = input;
41166
+ this.options = resolveOptions(input.options);
41167
+ this.copperPourPairContexts = getCopperPourPairContexts(input, this.options);
41168
+ this.stitchingObstacles = getStitchingObstacles(
41169
+ input.circuitJson,
41170
+ this.options.layers
41171
+ );
41172
+ const fallbackViaRadius = this.options.viaOuterDiameter / 2;
41173
+ for (const element of input.circuitJson) {
41174
+ if (element.type === "pcb_via") {
41175
+ const pcbVia = element;
41176
+ this.existingPcbViaIds.add(pcbVia.pcb_via_id);
41177
+ this.occupiedVias.push({
41178
+ center: { x: pcbVia.x, y: pcbVia.y },
41179
+ radius: pcbVia.outer_diameter / 2
41180
+ });
41181
+ } else if (element.type === "pcb_trace") {
41182
+ for (const routePoint of element.route) {
41183
+ if (routePoint.route_type !== "via") continue;
41184
+ this.occupiedVias.push({
41185
+ center: { x: routePoint.x, y: routePoint.y },
41186
+ radius: getPcbTraceViaRadius(routePoint, fallbackViaRadius)
41187
+ });
41188
+ }
41189
+ }
41190
+ }
41191
+ }
41192
+ input;
41193
+ options;
41194
+ copperPourPairContexts;
41195
+ pcbVias = [];
41196
+ occupiedVias = [];
41197
+ existingPcbViaIds = /* @__PURE__ */ new Set();
41198
+ stitchingObstacles;
41199
+ nextCopperPourPairIndex = 0;
41200
+ nextViaId = 0;
41201
+ _step() {
41202
+ const copperPourPairContext = this.copperPourPairContexts[this.nextCopperPourPairIndex];
41203
+ if (!copperPourPairContext) {
41204
+ this.solved = true;
41205
+ this.progress = 1;
41206
+ return;
41207
+ }
41208
+ this.processCopperPourPair(copperPourPairContext);
41209
+ this.nextCopperPourPairIndex += 1;
41210
+ this.progress = this.copperPourPairContexts.length === 0 ? 1 : this.nextCopperPourPairIndex / this.copperPourPairContexts.length;
41211
+ this.solved = this.nextCopperPourPairIndex === this.copperPourPairContexts.length;
41212
+ }
41213
+ processCopperPourPair(context) {
41214
+ const [fromLayer, toLayer] = this.options.layers;
41215
+ const fromLayerShapes = context.fromLayerPours.map(
41216
+ (copperPour) => copperPour.brep_shape
41217
+ );
41218
+ const toLayerShapes = context.toLayerPours.map(
41219
+ (copperPour) => copperPour.brep_shape
41220
+ );
41221
+ const fromBounds = getShapeUnionBounds(fromLayerShapes);
41222
+ const toBounds = getShapeUnionBounds(toLayerShapes);
41223
+ if (!fromBounds || !toBounds) return;
41224
+ const overlapBounds = {
41225
+ minX: Math.max(fromBounds.minX, toBounds.minX),
41226
+ maxX: Math.min(fromBounds.maxX, toBounds.maxX),
41227
+ minY: Math.max(fromBounds.minY, toBounds.minY),
41228
+ maxY: Math.min(fromBounds.maxY, toBounds.maxY)
41229
+ };
41230
+ if (overlapBounds.minX > overlapBounds.maxX || overlapBounds.minY > overlapBounds.maxY) {
41231
+ return;
41232
+ }
41233
+ const viaRadius = this.options.viaOuterDiameter / 2;
41234
+ const requiredCopperRadius = viaRadius + this.options.pourEdgeClearance;
41235
+ const requiredObstacleRadius = viaRadius + this.options.obstacleClearance;
41236
+ const xCoordinates = getGridCoordinates({
41237
+ minimum: overlapBounds.minX + requiredCopperRadius,
41238
+ maximum: overlapBounds.maxX - requiredCopperRadius,
41239
+ origin: this.options.gridOrigin.x,
41240
+ pitch: this.options.viaPitch
41241
+ });
41242
+ const yCoordinates = getGridCoordinates({
41243
+ minimum: overlapBounds.minY + requiredCopperRadius,
41244
+ maximum: overlapBounds.maxY - requiredCopperRadius,
41245
+ origin: this.options.gridOrigin.y,
41246
+ pitch: this.options.viaPitch
41247
+ });
41248
+ for (const y of yCoordinates) {
41249
+ for (const x of xCoordinates) {
41250
+ const center = { x, y };
41251
+ if (isTooCloseToOccupiedVia({
41252
+ center,
41253
+ radius: viaRadius,
41254
+ occupiedVias: this.occupiedVias,
41255
+ minimumViaSeparation: this.options.minimumViaSeparation
41256
+ }) || doesViaIntersectStitchingObstacle({
41257
+ center,
41258
+ radius: requiredObstacleRadius,
41259
+ obstacles: this.stitchingObstacles
41260
+ }) || !isViaAnnulusInsideShapeUnion({
41261
+ center,
41262
+ radius: requiredCopperRadius,
41263
+ shapes: fromLayerShapes
41264
+ }) || !isViaAnnulusInsideShapeUnion({
41265
+ center,
41266
+ radius: requiredCopperRadius,
41267
+ shapes: toLayerShapes
41268
+ })) {
41269
+ continue;
41270
+ }
41271
+ let pcbViaId = `via_stitch_via_${this.nextViaId++}`;
41272
+ while (this.existingPcbViaIds.has(pcbViaId)) {
41273
+ pcbViaId = `via_stitch_via_${this.nextViaId++}`;
41274
+ }
41275
+ const referencePour = context.fromLayerPours[0];
41276
+ const pcbVia = {
41277
+ type: "pcb_via",
41278
+ pcb_via_id: pcbViaId,
41279
+ x,
41280
+ y,
41281
+ hole_diameter: this.options.viaHoleDiameter,
41282
+ outer_diameter: this.options.viaOuterDiameter,
41283
+ layers: [fromLayer, toLayer],
41284
+ from_layer: fromLayer,
41285
+ to_layer: toLayer,
41286
+ source_net_id: context.sourceNetId,
41287
+ subcircuit_id: referencePour.subcircuit_id,
41288
+ pcb_group_id: referencePour.pcb_group_id,
41289
+ subcircuit_connectivity_map_key: context.sourceNet?.subcircuit_connectivity_map_key,
41290
+ is_tented: this.options.isTented
41291
+ };
41292
+ this.pcbVias.push(pcbVia);
41293
+ this.existingPcbViaIds.add(pcbViaId);
41294
+ this.occupiedVias.push({ center, radius: viaRadius });
41295
+ }
41296
+ }
41297
+ }
41298
+ getOutput() {
41299
+ return {
41300
+ processedCopperPourPairCount: this.copperPourPairContexts.length,
41301
+ pcbVias: this.pcbVias
41302
+ };
41303
+ }
41304
+ };
41305
+
41306
+ // lib/solvers.ts
40822
41307
  import { PackSolver2 } from "calculate-packing";
40823
41308
  var SOLVERS = {
40824
41309
  PackSolver2,
@@ -40838,7 +41323,8 @@ var SOLVERS = {
40838
41323
  CreateFdmEnclosureSolver,
40839
41324
  FanoutSolver,
40840
41325
  ImplicitCopperPourPipelineSolver,
40841
- SchematicTracePipelineSolver
41326
+ SchematicTracePipelineSolver,
41327
+ ViaStitchSolver
40842
41328
  };
40843
41329
 
40844
41330
  // lib/utils/autorouting/LocalCacheEngineCacheProvider.ts
@@ -50925,7 +51411,7 @@ function Group_getRoutingPhasePlans(group) {
50925
51411
  var package_default = {
50926
51412
  name: "@tscircuit/core",
50927
51413
  type: "module",
50928
- version: "0.0.1857",
51414
+ version: "0.0.1858",
50929
51415
  types: "dist/index.d.ts",
50930
51416
  main: "dist/index.js",
50931
51417
  module: "dist/index.js",
@@ -50983,6 +51469,7 @@ var package_default = {
50983
51469
  "@tscircuit/schematic-trace-solver": "^0.0.186",
50984
51470
  "@tscircuit/solver-utils": "^0.0.16",
50985
51471
  "@tscircuit/soup-util": "^0.0.41",
51472
+ "@tscircuit/via-stitch-solver": "github:tscircuit/via-stitch-solver#75653b6440e75584b052f03595afd34283ae7558",
50986
51473
  "@tscircuit/winding-breakout-point-solver": "github:tscircuit/winding-breakout-point-solver#202dbe9eb0088633b6fa094120dba6f2f41f8803",
50987
51474
  "@types/bun": "^1.2.16",
50988
51475
  "@types/debug": "^4.1.12",
@@ -51654,7 +52141,7 @@ function getAccumulatedPcbTracesWithStageOutputReplacements({
51654
52141
  // lib/components/primitive-components/Group/get-source-trace-id-for-routed-trace.ts
51655
52142
  import { distance as distance14, pointToSegmentDistance as pointToSegmentDistance3 } from "@tscircuit/math-utils";
51656
52143
  import { ConnectivityMap as ConnectivityMap5 } from "circuit-json-to-connectivity-map";
51657
- var POINT_EPSILON = 1e-6;
52144
+ var POINT_EPSILON2 = 1e-6;
51658
52145
  function isPointOnWireSegment({
51659
52146
  point: point6,
51660
52147
  segmentStart,
@@ -51663,7 +52150,7 @@ function isPointOnWireSegment({
51663
52150
  if (point6.layer && (segmentStart.layer !== point6.layer || segmentEnd.layer !== point6.layer)) {
51664
52151
  return false;
51665
52152
  }
51666
- return pointToSegmentDistance3(point6, segmentStart, segmentEnd) <= POINT_EPSILON;
52153
+ return pointToSegmentDistance3(point6, segmentStart, segmentEnd) <= POINT_EPSILON2;
51667
52154
  }
51668
52155
  function isPointInSmtPad({
51669
52156
  point: point6,
@@ -55449,6 +55936,8 @@ var IsolatedCircuit = class {
55449
55936
  pcbDisabled = false;
55450
55937
  pcbRoutingDisabled = false;
55451
55938
  _featureMspSchematicTraceRouting = true;
55939
+ /** Experimental automatic via stitching; opt in before rendering. */
55940
+ _featurePcbViaStitching = false;
55452
55941
  /**
55453
55942
  * The IsolatedCircuit name is usually set by the platform, it's not required but
55454
55943
  * if supplied can identify the circuit in certain effects, e.g. it is passed
@@ -55873,7 +56362,7 @@ import {
55873
56362
  // lib/components/primitive-components/CopperPour/utils/mark-trace-segments-inside-copper-pour.ts
55874
56363
  var EPSILON14 = 1e-9;
55875
56364
  var isWireRoutePoint = (routePoint) => routePoint.route_type === "wire";
55876
- var isPointOnSegment = (p, a, b) => {
56365
+ var isPointOnSegment2 = (p, a, b) => {
55877
56366
  const cross3 = (p.y - a.y) * (b.x - a.x) - (p.x - a.x) * (b.y - a.y);
55878
56367
  if (Math.abs(cross3) > EPSILON14) return false;
55879
56368
  const dot = (p.x - a.x) * (b.x - a.x) + (p.y - a.y) * (b.y - a.y);
@@ -55882,12 +56371,12 @@ var isPointOnSegment = (p, a, b) => {
55882
56371
  if (dot - squaredLength > EPSILON14) return false;
55883
56372
  return true;
55884
56373
  };
55885
- var isPointInRing = (point6, ring) => {
56374
+ var isPointInRing2 = (point6, ring) => {
55886
56375
  if (ring.length < 3) return false;
55887
56376
  let inside = false;
55888
56377
  let previous = ring[ring.length - 1];
55889
56378
  for (const current of ring) {
55890
- if (isPointOnSegment(point6, previous, current)) return true;
56379
+ if (isPointOnSegment2(point6, previous, current)) return true;
55891
56380
  const intersects = current.y > point6.y !== previous.y > point6.y && point6.x < (previous.x - current.x) * (point6.y - current.y) / (previous.y - current.y) + current.x;
55892
56381
  if (intersects) inside = !inside;
55893
56382
  previous = current;
@@ -55910,10 +56399,10 @@ var isPointInBrepPour = (p, pour) => {
55910
56399
  x: v.x,
55911
56400
  y: v.y
55912
56401
  }));
55913
- if (!isPointInRing(p, outerRing)) return false;
56402
+ if (!isPointInRing2(p, outerRing)) return false;
55914
56403
  for (const innerRing of pour.brep_shape.inner_rings) {
55915
56404
  const points = innerRing.vertices.map((v) => ({ x: v.x, y: v.y }));
55916
- if (isPointInRing(p, points)) return false;
56405
+ if (isPointInRing2(p, points)) return false;
55917
56406
  }
55918
56407
  return true;
55919
56408
  };
@@ -56100,6 +56589,59 @@ function CopperPour_doInitialPcbCopperPourRender(copperPour) {
56100
56589
  });
56101
56590
  }
56102
56591
 
56592
+ // lib/components/primitive-components/CopperPour/CopperPour_doInitialPcbViaStitchRender.ts
56593
+ var renderViaStitchingForCopperPours = (copperPour) => {
56594
+ const subcircuit = copperPour.getSubcircuit();
56595
+ if (!subcircuit.root) return;
56596
+ const copperPours = subcircuit.selectAll("copperpour").filter(
56597
+ (candidateCopperPour) => candidateCopperPour.getSubcircuit() === subcircuit
56598
+ );
56599
+ if (copperPours[0] !== copperPour) return;
56600
+ const sourceNetIds = copperPours.flatMap((candidateCopperPour) => {
56601
+ const net = subcircuit.selectOne(
56602
+ candidateCopperPour._parsedProps.connectsTo
56603
+ );
56604
+ return net?.source_net_id ? [net.source_net_id] : [];
56605
+ });
56606
+ if (sourceNetIds.length === 0) return;
56607
+ const { db } = subcircuit.root;
56608
+ const pcbStyle = copperPour.getInheritedMergedProperty("pcbStyle");
56609
+ const { holeDiameter, padDiameter } = getViaDiameterDefaults(pcbStyle);
56610
+ const boardComponent = copperPour._getBoard();
56611
+ const pcbBoard = boardComponent?.pcb_board_id ? db.pcb_board.get(boardComponent.pcb_board_id) : void 0;
56612
+ const solverInput = {
56613
+ circuitJson: db.toArray(),
56614
+ options: {
56615
+ sourceNetIds: [...new Set(sourceNetIds)],
56616
+ viaHoleDiameter: pcbBoard?.min_via_hole_diameter ?? holeDiameter,
56617
+ viaOuterDiameter: pcbBoard?.min_via_pad_diameter ?? padDiameter
56618
+ }
56619
+ };
56620
+ const solver = new ViaStitchSolver(solverInput);
56621
+ subcircuit.root.emit("solver:started", {
56622
+ type: "solver:started",
56623
+ solverName: "ViaStitchSolver",
56624
+ solverParams: solverInput,
56625
+ solverConstructorArgs: [solverInput],
56626
+ componentName: subcircuit.getString()
56627
+ });
56628
+ solver.solve();
56629
+ if (solver.failed) {
56630
+ throw new Error(solver.error ?? "Via stitching solver failed");
56631
+ }
56632
+ for (const pcbVia of solver.getOutput().pcbVias) {
56633
+ const { pcb_via_id: _solverViaId, ...pcbViaInput } = pcbVia;
56634
+ db.pcb_via.insert(pcbViaInput);
56635
+ }
56636
+ };
56637
+ function CopperPour_doInitialPcbViaStitchRender(copperPour) {
56638
+ if (copperPour.root?.pcbDisabled || !copperPour.root?._featurePcbViaStitching)
56639
+ return;
56640
+ copperPour._queueAsyncEffect("PcbViaStitchRender", async () => {
56641
+ renderViaStitchingForCopperPours(copperPour);
56642
+ });
56643
+ }
56644
+
56103
56645
  // lib/components/primitive-components/CopperPour/CopperPour.ts
56104
56646
  var CopperPour = class extends PrimitiveComponent2 {
56105
56647
  isPcbPrimitive = true;
@@ -56120,6 +56662,9 @@ var CopperPour = class extends PrimitiveComponent2 {
56120
56662
  doInitialPcbCopperPourRender() {
56121
56663
  CopperPour_doInitialPcbCopperPourRender(this);
56122
56664
  }
56665
+ doInitialPcbViaStitchRender() {
56666
+ CopperPour_doInitialPcbViaStitchRender(this);
56667
+ }
56123
56668
  };
56124
56669
 
56125
56670
  // lib/components/normal-components/Board_doInitialPcbImplicitCopperPourRender.ts
@@ -60225,7 +60770,7 @@ var validateWindingBreakoutInput = (input) => {
60225
60770
  };
60226
60771
 
60227
60772
  // node_modules/@tscircuit/winding-breakout-point-solver/lib/solvers/GatePlacementSolver.ts
60228
- import { BaseSolver as BaseSolver3 } from "@tscircuit/solver-utils";
60773
+ import { BaseSolver as BaseSolver4 } from "@tscircuit/solver-utils";
60229
60774
 
60230
60775
  // node_modules/@tscircuit/winding-breakout-point-solver/lib/gate-placement/place-breakout-gates.ts
60231
60776
  var GEOMETRY_EPSILON = 1e-9;
@@ -60755,7 +61300,7 @@ var getSharedGateSlotCount = (points) => new Set(
60755
61300
  (point6) => `${point6.regionId}:${point6.x.toFixed(9)}:${point6.y.toFixed(9)}`
60756
61301
  )
60757
61302
  ).size;
60758
- var GatePlacementSolver = class extends BaseSolver3 {
61303
+ var GatePlacementSolver = class extends BaseSolver4 {
60759
61304
  constructor(params) {
60760
61305
  super();
60761
61306
  this.params = params;
@@ -60894,7 +61439,7 @@ var GatePlacementSolver = class extends BaseSolver3 {
60894
61439
  };
60895
61440
 
60896
61441
  // node_modules/@tscircuit/winding-breakout-point-solver/lib/solvers/ReferenceOrderingSolver.ts
60897
- import { BaseSolver as BaseSolver4 } from "@tscircuit/solver-utils";
61442
+ import { BaseSolver as BaseSolver5 } from "@tscircuit/solver-utils";
60898
61443
 
60899
61444
  // node_modules/@tscircuit/winding-breakout-point-solver/lib/ordering/get-natural-winding-order.ts
60900
61445
  var getNaturalWindingOrder = (region, connections) => connections.map((connection) => {
@@ -60961,7 +61506,7 @@ var getReferenceWindingOrder = (naturalOrder, atomicGroups, buses) => {
60961
61506
  };
60962
61507
 
60963
61508
  // node_modules/@tscircuit/winding-breakout-point-solver/lib/solvers/ReferenceOrderingSolver.ts
60964
- var ReferenceOrderingSolver = class extends BaseSolver4 {
61509
+ var ReferenceOrderingSolver = class extends BaseSolver5 {
60965
61510
  constructor(params) {
60966
61511
  super();
60967
61512
  this.params = params;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tscircuit/core",
3
3
  "type": "module",
4
- "version": "0.0.1858",
4
+ "version": "0.0.1859",
5
5
  "types": "dist/index.d.ts",
6
6
  "main": "dist/index.js",
7
7
  "module": "dist/index.js",
@@ -59,6 +59,7 @@
59
59
  "@tscircuit/schematic-trace-solver": "^0.0.186",
60
60
  "@tscircuit/solver-utils": "^0.0.16",
61
61
  "@tscircuit/soup-util": "^0.0.41",
62
+ "@tscircuit/via-stitch-solver": "github:tscircuit/via-stitch-solver#75653b6440e75584b052f03595afd34283ae7558",
62
63
  "@tscircuit/winding-breakout-point-solver": "github:tscircuit/winding-breakout-point-solver#202dbe9eb0088633b6fa094120dba6f2f41f8803",
63
64
  "@types/bun": "^1.2.16",
64
65
  "@types/debug": "^4.1.12",