@tscircuit/core 0.0.1858 → 0.0.1860

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",
@@ -3316,6 +3327,26 @@ var getObstaclesFromCircuitJson = (circuitJson, connMap) => {
3316
3327
  height: element.outer_diameter,
3317
3328
  connectedTo: withNetId([element.pcb_plated_hole_id])
3318
3329
  });
3330
+ } else if (element.shape === "pill_hole_with_rect_pad" || element.shape === "rotated_pill_hole_with_rect_pad") {
3331
+ const rotatedRect = {
3332
+ center: { x: element.x, y: element.y },
3333
+ width: element.rect_pad_width,
3334
+ height: element.rect_pad_height,
3335
+ rotation: element.shape === "rotated_pill_hole_with_rect_pad" ? element.rect_ccw_rotation : 0
3336
+ };
3337
+ const axisAlignedRect = getAxisAlignedRectFromRotatedRect(rotatedRect);
3338
+ const rect = axisAlignedRect ?? rotatedRect;
3339
+ obstacles.push({
3340
+ circuitJsonMetadata: pcbPlatedHoleCircuitJsonMetadata,
3341
+ componentId: pcbComponentId,
3342
+ type: "rect",
3343
+ layers: everyLayer,
3344
+ center: rect.center,
3345
+ width: rect.width,
3346
+ height: rect.height,
3347
+ ccwRotationDegrees: axisAlignedRect ? void 0 : rotatedRect.rotation,
3348
+ connectedTo: withNetId([element.pcb_plated_hole_id])
3349
+ });
3319
3350
  } else if (element.shape === "circular_hole_with_rect_pad") {
3320
3351
  obstacles.push({
3321
3352
  circuitJsonMetadata: pcbPlatedHoleCircuitJsonMetadata,
@@ -40819,6 +40850,480 @@ var ImplicitCopperPourPipelineSolver = class extends BasePipelineSolver {
40819
40850
  // lib/solvers.ts
40820
40851
  import { LayoutPipelineSolver } from "@tscircuit/matchpack";
40821
40852
  import { SchematicTracePipelineSolver } from "@tscircuit/schematic-trace-solver";
40853
+
40854
+ // node_modules/@tscircuit/via-stitch-solver/lib/solvers/ViaStitchSolver.ts
40855
+ import { BaseSolver as BaseSolver3 } from "@tscircuit/solver-utils";
40856
+
40857
+ // node_modules/@tscircuit/via-stitch-solver/lib/geometry/brep-point-containment.ts
40858
+ var POINT_EPSILON = 1e-8;
40859
+ var isPointOnSegment = (point6, start, end) => {
40860
+ const cross3 = (point6.y - start.y) * (end.x - start.x) - (point6.x - start.x) * (end.y - start.y);
40861
+ if (Math.abs(cross3) > POINT_EPSILON) return false;
40862
+ const dot = (point6.x - start.x) * (end.x - start.x) + (point6.y - start.y) * (end.y - start.y);
40863
+ if (dot < -POINT_EPSILON) return false;
40864
+ const squaredLength = (end.x - start.x) ** 2 + (end.y - start.y) ** 2;
40865
+ return dot <= squaredLength + POINT_EPSILON;
40866
+ };
40867
+ var isPointInRing = (point6, ring) => {
40868
+ let isInside = false;
40869
+ for (let currentIndex = 0, previousIndex = ring.vertices.length - 1; currentIndex < ring.vertices.length; previousIndex = currentIndex++) {
40870
+ const current = ring.vertices[currentIndex];
40871
+ const previous = ring.vertices[previousIndex];
40872
+ if (isPointOnSegment(point6, previous, current)) return true;
40873
+ 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;
40874
+ if (crossesRay) isInside = !isInside;
40875
+ }
40876
+ return isInside;
40877
+ };
40878
+ var isPointInShape = (point6, shape) => isPointInRing(point6, shape.outer_ring) && !shape.inner_rings.some((innerRing) => isPointInRing(point6, innerRing));
40879
+ var isPointInShapeUnion = (point6, shapes) => shapes.some((shape) => isPointInShape(point6, shape));
40880
+ var getShapeUnionBounds = (shapes) => {
40881
+ const vertices = shapes.flatMap((shape) => shape.outer_ring.vertices);
40882
+ if (vertices.length === 0) return void 0;
40883
+ return {
40884
+ minX: Math.min(...vertices.map((vertex) => vertex.x)),
40885
+ maxX: Math.max(...vertices.map((vertex) => vertex.x)),
40886
+ minY: Math.min(...vertices.map((vertex) => vertex.y)),
40887
+ maxY: Math.max(...vertices.map((vertex) => vertex.y))
40888
+ };
40889
+ };
40890
+ var isViaAnnulusInsideShapeUnion = ({
40891
+ center,
40892
+ radius,
40893
+ shapes
40894
+ }) => {
40895
+ const samplePoints = [center];
40896
+ for (let sampleIndex = 0; sampleIndex < 32; sampleIndex++) {
40897
+ const angle = sampleIndex / 32 * Math.PI * 2;
40898
+ samplePoints.push({
40899
+ x: center.x + Math.cos(angle) * radius,
40900
+ y: center.y + Math.sin(angle) * radius
40901
+ });
40902
+ }
40903
+ return samplePoints.every(
40904
+ (samplePoint) => isPointInShapeUnion(samplePoint, shapes)
40905
+ );
40906
+ };
40907
+
40908
+ // node_modules/@tscircuit/via-stitch-solver/lib/geometry/circuit-element-obstacles.ts
40909
+ var layerMatches = (layer, layers) => layers.some((candidateLayer) => String(candidateLayer) === String(layer));
40910
+ var componentToObstacle = (component) => {
40911
+ if (component.do_not_place || !component.obstructs_within_bounds) {
40912
+ return void 0;
40913
+ }
40914
+ return {
40915
+ kind: "rect",
40916
+ center: component.center,
40917
+ width: component.width,
40918
+ height: component.height,
40919
+ ccwRotation: component.rotation
40920
+ };
40921
+ };
40922
+ var smtPadToObstacle = (smtPad) => {
40923
+ if (smtPad.shape === "circle") {
40924
+ return {
40925
+ kind: "circle",
40926
+ center: { x: smtPad.x, y: smtPad.y },
40927
+ radius: smtPad.radius
40928
+ };
40929
+ }
40930
+ if (smtPad.shape === "polygon") {
40931
+ return { kind: "polygon", points: smtPad.points };
40932
+ }
40933
+ return {
40934
+ kind: "rect",
40935
+ center: { x: smtPad.x, y: smtPad.y },
40936
+ width: smtPad.width,
40937
+ height: smtPad.height,
40938
+ ccwRotation: smtPad.shape === "rotated_rect" || smtPad.shape === "rotated_pill" ? smtPad.ccw_rotation : 0
40939
+ };
40940
+ };
40941
+ var platedHoleToObstacle = (platedHole) => {
40942
+ if (platedHole.shape === "circle") {
40943
+ return {
40944
+ kind: "circle",
40945
+ center: { x: platedHole.x, y: platedHole.y },
40946
+ radius: platedHole.outer_diameter / 2
40947
+ };
40948
+ }
40949
+ if ("outer_width" in platedHole) {
40950
+ return {
40951
+ kind: "rect",
40952
+ center: { x: platedHole.x, y: platedHole.y },
40953
+ width: platedHole.outer_width,
40954
+ height: platedHole.outer_height,
40955
+ ccwRotation: platedHole.ccw_rotation
40956
+ };
40957
+ }
40958
+ if (platedHole.shape === "hole_with_polygon_pad") {
40959
+ const rotationRadians = (platedHole.ccw_rotation ?? 0) * Math.PI / 180;
40960
+ const cosine = Math.cos(rotationRadians);
40961
+ const sine = Math.sin(rotationRadians);
40962
+ return {
40963
+ kind: "polygon",
40964
+ points: platedHole.pad_outline.map((point6) => ({
40965
+ x: platedHole.x + point6.x * cosine - point6.y * sine,
40966
+ y: platedHole.y + point6.x * sine + point6.y * cosine
40967
+ }))
40968
+ };
40969
+ }
40970
+ return {
40971
+ kind: "rect",
40972
+ center: { x: platedHole.x, y: platedHole.y },
40973
+ width: platedHole.rect_pad_width,
40974
+ height: platedHole.rect_pad_height,
40975
+ ccwRotation: "rect_ccw_rotation" in platedHole ? platedHole.rect_ccw_rotation ?? 0 : 0
40976
+ };
40977
+ };
40978
+ var holeToObstacle = (hole) => {
40979
+ if ("hole_diameter" in hole) {
40980
+ if (hole.hole_shape === "circle") {
40981
+ return {
40982
+ kind: "circle",
40983
+ center: { x: hole.x, y: hole.y },
40984
+ radius: hole.hole_diameter / 2
40985
+ };
40986
+ }
40987
+ return {
40988
+ kind: "rect",
40989
+ center: { x: hole.x, y: hole.y },
40990
+ width: hole.hole_diameter,
40991
+ height: hole.hole_diameter,
40992
+ ccwRotation: 0
40993
+ };
40994
+ }
40995
+ return {
40996
+ kind: "rect",
40997
+ center: { x: hole.x, y: hole.y },
40998
+ width: hole.hole_width,
40999
+ height: hole.hole_height,
41000
+ ccwRotation: hole.hole_shape === "rotated_pill" ? hole.ccw_rotation : 0
41001
+ };
41002
+ };
41003
+ var getDistanceToSegment = (point6, start, end) => {
41004
+ const segmentX = end.x - start.x;
41005
+ const segmentY = end.y - start.y;
41006
+ const squaredLength = segmentX ** 2 + segmentY ** 2;
41007
+ if (squaredLength === 0)
41008
+ return Math.hypot(point6.x - start.x, point6.y - start.y);
41009
+ const projection = Math.max(
41010
+ 0,
41011
+ Math.min(
41012
+ 1,
41013
+ ((point6.x - start.x) * segmentX + (point6.y - start.y) * segmentY) / squaredLength
41014
+ )
41015
+ );
41016
+ return Math.hypot(
41017
+ point6.x - (start.x + projection * segmentX),
41018
+ point6.y - (start.y + projection * segmentY)
41019
+ );
41020
+ };
41021
+ var isPointInPolygon = (point6, polygon) => {
41022
+ let isInside = false;
41023
+ for (let currentIndex = 0, previousIndex = polygon.length - 1; currentIndex < polygon.length; previousIndex = currentIndex++) {
41024
+ const current = polygon[currentIndex];
41025
+ const previous = polygon[previousIndex];
41026
+ 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;
41027
+ if (crossesRay) isInside = !isInside;
41028
+ }
41029
+ return isInside;
41030
+ };
41031
+ var doesCircleIntersectObstacle = (center, radius, obstacle) => {
41032
+ if (obstacle.kind === "circle") {
41033
+ return Math.hypot(center.x - obstacle.center.x, center.y - obstacle.center.y) < radius + obstacle.radius;
41034
+ }
41035
+ if (obstacle.kind === "polygon") {
41036
+ if (isPointInPolygon(center, obstacle.points)) return true;
41037
+ return obstacle.points.some(
41038
+ (point6, pointIndex) => Boolean(
41039
+ getDistanceToSegment(
41040
+ center,
41041
+ point6,
41042
+ obstacle.points[(pointIndex + 1) % obstacle.points.length]
41043
+ ) < radius
41044
+ )
41045
+ );
41046
+ }
41047
+ const rotationRadians = -obstacle.ccwRotation * Math.PI / 180;
41048
+ const deltaX = center.x - obstacle.center.x;
41049
+ const deltaY = center.y - obstacle.center.y;
41050
+ const localX = deltaX * Math.cos(rotationRadians) - deltaY * Math.sin(rotationRadians);
41051
+ const localY = deltaX * Math.sin(rotationRadians) + deltaY * Math.cos(rotationRadians);
41052
+ const outsideX = Math.max(Math.abs(localX) - obstacle.width / 2, 0);
41053
+ const outsideY = Math.max(Math.abs(localY) - obstacle.height / 2, 0);
41054
+ return Math.hypot(outsideX, outsideY) < radius;
41055
+ };
41056
+ var getStitchingObstacles = (circuitJson, layers) => circuitJson.flatMap((element) => {
41057
+ if (element.type === "pcb_component" && layerMatches(element.layer, layers)) {
41058
+ const obstacle = componentToObstacle(element);
41059
+ return obstacle ? [obstacle] : [];
41060
+ }
41061
+ if (element.type === "pcb_smtpad" && layerMatches(element.layer, layers)) {
41062
+ return [smtPadToObstacle(element)];
41063
+ }
41064
+ if (element.type === "pcb_plated_hole" && element.layers.some((layer) => layerMatches(layer, layers))) {
41065
+ return [platedHoleToObstacle(element)];
41066
+ }
41067
+ if (element.type === "pcb_hole") return [holeToObstacle(element)];
41068
+ return [];
41069
+ });
41070
+ var doesViaIntersectStitchingObstacle = ({
41071
+ center,
41072
+ radius,
41073
+ obstacles
41074
+ }) => obstacles.some(
41075
+ (obstacle) => doesCircleIntersectObstacle(center, radius, obstacle)
41076
+ );
41077
+
41078
+ // node_modules/@tscircuit/via-stitch-solver/lib/solvers/ViaStitchSolver.ts
41079
+ var resolveOptions = (options = {}) => {
41080
+ const resolvedOptions = {
41081
+ sourceNetIds: options.sourceNetIds ? new Set(options.sourceNetIds) : void 0,
41082
+ layers: options.layers ?? ["top", "bottom"],
41083
+ viaPitch: options.viaPitch ?? 1,
41084
+ viaHoleDiameter: options.viaHoleDiameter ?? 0.3,
41085
+ viaOuterDiameter: options.viaOuterDiameter ?? 0.6,
41086
+ pourEdgeClearance: options.pourEdgeClearance ?? 0.2,
41087
+ obstacleClearance: options.obstacleClearance ?? 0.2,
41088
+ minimumViaSeparation: options.minimumViaSeparation ?? Math.max(options.viaOuterDiameter ?? 0.6, 0.8),
41089
+ gridOrigin: options.gridOrigin ?? { x: 0, y: 0 },
41090
+ isTented: options.isTented ?? true
41091
+ };
41092
+ for (const [optionName, optionValue] of [
41093
+ ["viaPitch", resolvedOptions.viaPitch],
41094
+ ["viaHoleDiameter", resolvedOptions.viaHoleDiameter],
41095
+ ["viaOuterDiameter", resolvedOptions.viaOuterDiameter],
41096
+ ["minimumViaSeparation", resolvedOptions.minimumViaSeparation]
41097
+ ]) {
41098
+ if (!Number.isFinite(optionValue) || optionValue <= 0) {
41099
+ throw new Error(`${optionName} must be a finite number greater than zero`);
41100
+ }
41101
+ }
41102
+ if (!Number.isFinite(resolvedOptions.pourEdgeClearance) || resolvedOptions.pourEdgeClearance < 0) {
41103
+ throw new Error("pourEdgeClearance must be a finite non-negative number");
41104
+ }
41105
+ if (!Number.isFinite(resolvedOptions.obstacleClearance) || resolvedOptions.obstacleClearance < 0) {
41106
+ throw new Error("obstacleClearance must be a finite non-negative number");
41107
+ }
41108
+ if (!Number.isFinite(resolvedOptions.gridOrigin.x) || !Number.isFinite(resolvedOptions.gridOrigin.y)) {
41109
+ throw new Error("gridOrigin coordinates must be finite numbers");
41110
+ }
41111
+ if (resolvedOptions.viaHoleDiameter >= resolvedOptions.viaOuterDiameter) {
41112
+ throw new Error("viaHoleDiameter must be smaller than viaOuterDiameter");
41113
+ }
41114
+ if (String(resolvedOptions.layers[0]) === String(resolvedOptions.layers[1])) {
41115
+ throw new Error("layers must contain two distinct PCB layers");
41116
+ }
41117
+ return resolvedOptions;
41118
+ };
41119
+ var isBrepCopperPour = (element) => element.type === "pcb_copper_pour" && element.shape === "brep";
41120
+ var getCopperPourPairContexts = (input, options) => {
41121
+ const sourceNetsById = new Map(
41122
+ input.circuitJson.filter((element) => element.type === "source_net").map((sourceNet) => [sourceNet.source_net_id, sourceNet])
41123
+ );
41124
+ const poursBySourceNetId = /* @__PURE__ */ new Map();
41125
+ for (const element of input.circuitJson) {
41126
+ if (!isBrepCopperPour(element) || !element.source_net_id) continue;
41127
+ if (options.sourceNetIds && !options.sourceNetIds.has(element.source_net_id)) {
41128
+ continue;
41129
+ }
41130
+ const sourceNetPours = poursBySourceNetId.get(element.source_net_id) ?? [];
41131
+ sourceNetPours.push(element);
41132
+ poursBySourceNetId.set(element.source_net_id, sourceNetPours);
41133
+ }
41134
+ const [fromLayer, toLayer] = options.layers;
41135
+ const contexts = [];
41136
+ for (const [sourceNetId, sourceNetPours] of poursBySourceNetId) {
41137
+ const fromLayerPours = sourceNetPours.filter(
41138
+ (copperPour) => String(copperPour.layer) === String(fromLayer)
41139
+ );
41140
+ const toLayerPours = sourceNetPours.filter(
41141
+ (copperPour) => String(copperPour.layer) === String(toLayer)
41142
+ );
41143
+ if (fromLayerPours.length === 0 || toLayerPours.length === 0) continue;
41144
+ contexts.push({
41145
+ sourceNetId,
41146
+ sourceNet: sourceNetsById.get(sourceNetId),
41147
+ fromLayerPours,
41148
+ toLayerPours
41149
+ });
41150
+ }
41151
+ return contexts;
41152
+ };
41153
+ var getPcbTraceViaRadius = (routePoint, fallbackRadius) => {
41154
+ const routePointWithDiameter = routePoint;
41155
+ return (routePointWithDiameter.outer_diameter ?? fallbackRadius * 2) / 2;
41156
+ };
41157
+ var isTooCloseToOccupiedVia = ({
41158
+ center,
41159
+ radius,
41160
+ occupiedVias,
41161
+ minimumViaSeparation
41162
+ }) => occupiedVias.some(
41163
+ (occupiedVia) => Math.hypot(
41164
+ center.x - occupiedVia.center.x,
41165
+ center.y - occupiedVia.center.y
41166
+ ) < Math.max(minimumViaSeparation, radius + occupiedVia.radius)
41167
+ );
41168
+ var getGridCoordinates = ({
41169
+ minimum,
41170
+ maximum,
41171
+ origin,
41172
+ pitch
41173
+ }) => {
41174
+ const coordinates = [];
41175
+ const firstGridIndex = Math.ceil((minimum - origin) / pitch);
41176
+ const lastGridIndex = Math.floor((maximum - origin) / pitch);
41177
+ for (let gridIndex = firstGridIndex; gridIndex <= lastGridIndex; gridIndex++) {
41178
+ coordinates.push(origin + gridIndex * pitch);
41179
+ }
41180
+ return coordinates;
41181
+ };
41182
+ var ViaStitchSolver = class extends BaseSolver3 {
41183
+ constructor(input) {
41184
+ super();
41185
+ this.input = input;
41186
+ this.options = resolveOptions(input.options);
41187
+ this.copperPourPairContexts = getCopperPourPairContexts(input, this.options);
41188
+ this.stitchingObstacles = getStitchingObstacles(
41189
+ input.circuitJson,
41190
+ this.options.layers
41191
+ );
41192
+ const fallbackViaRadius = this.options.viaOuterDiameter / 2;
41193
+ for (const element of input.circuitJson) {
41194
+ if (element.type === "pcb_via") {
41195
+ const pcbVia = element;
41196
+ this.existingPcbViaIds.add(pcbVia.pcb_via_id);
41197
+ this.occupiedVias.push({
41198
+ center: { x: pcbVia.x, y: pcbVia.y },
41199
+ radius: pcbVia.outer_diameter / 2
41200
+ });
41201
+ } else if (element.type === "pcb_trace") {
41202
+ for (const routePoint of element.route) {
41203
+ if (routePoint.route_type !== "via") continue;
41204
+ this.occupiedVias.push({
41205
+ center: { x: routePoint.x, y: routePoint.y },
41206
+ radius: getPcbTraceViaRadius(routePoint, fallbackViaRadius)
41207
+ });
41208
+ }
41209
+ }
41210
+ }
41211
+ }
41212
+ input;
41213
+ options;
41214
+ copperPourPairContexts;
41215
+ pcbVias = [];
41216
+ occupiedVias = [];
41217
+ existingPcbViaIds = /* @__PURE__ */ new Set();
41218
+ stitchingObstacles;
41219
+ nextCopperPourPairIndex = 0;
41220
+ nextViaId = 0;
41221
+ _step() {
41222
+ const copperPourPairContext = this.copperPourPairContexts[this.nextCopperPourPairIndex];
41223
+ if (!copperPourPairContext) {
41224
+ this.solved = true;
41225
+ this.progress = 1;
41226
+ return;
41227
+ }
41228
+ this.processCopperPourPair(copperPourPairContext);
41229
+ this.nextCopperPourPairIndex += 1;
41230
+ this.progress = this.copperPourPairContexts.length === 0 ? 1 : this.nextCopperPourPairIndex / this.copperPourPairContexts.length;
41231
+ this.solved = this.nextCopperPourPairIndex === this.copperPourPairContexts.length;
41232
+ }
41233
+ processCopperPourPair(context) {
41234
+ const [fromLayer, toLayer] = this.options.layers;
41235
+ const fromLayerShapes = context.fromLayerPours.map(
41236
+ (copperPour) => copperPour.brep_shape
41237
+ );
41238
+ const toLayerShapes = context.toLayerPours.map(
41239
+ (copperPour) => copperPour.brep_shape
41240
+ );
41241
+ const fromBounds = getShapeUnionBounds(fromLayerShapes);
41242
+ const toBounds = getShapeUnionBounds(toLayerShapes);
41243
+ if (!fromBounds || !toBounds) return;
41244
+ const overlapBounds = {
41245
+ minX: Math.max(fromBounds.minX, toBounds.minX),
41246
+ maxX: Math.min(fromBounds.maxX, toBounds.maxX),
41247
+ minY: Math.max(fromBounds.minY, toBounds.minY),
41248
+ maxY: Math.min(fromBounds.maxY, toBounds.maxY)
41249
+ };
41250
+ if (overlapBounds.minX > overlapBounds.maxX || overlapBounds.minY > overlapBounds.maxY) {
41251
+ return;
41252
+ }
41253
+ const viaRadius = this.options.viaOuterDiameter / 2;
41254
+ const requiredCopperRadius = viaRadius + this.options.pourEdgeClearance;
41255
+ const requiredObstacleRadius = viaRadius + this.options.obstacleClearance;
41256
+ const xCoordinates = getGridCoordinates({
41257
+ minimum: overlapBounds.minX + requiredCopperRadius,
41258
+ maximum: overlapBounds.maxX - requiredCopperRadius,
41259
+ origin: this.options.gridOrigin.x,
41260
+ pitch: this.options.viaPitch
41261
+ });
41262
+ const yCoordinates = getGridCoordinates({
41263
+ minimum: overlapBounds.minY + requiredCopperRadius,
41264
+ maximum: overlapBounds.maxY - requiredCopperRadius,
41265
+ origin: this.options.gridOrigin.y,
41266
+ pitch: this.options.viaPitch
41267
+ });
41268
+ for (const y of yCoordinates) {
41269
+ for (const x of xCoordinates) {
41270
+ const center = { x, y };
41271
+ if (isTooCloseToOccupiedVia({
41272
+ center,
41273
+ radius: viaRadius,
41274
+ occupiedVias: this.occupiedVias,
41275
+ minimumViaSeparation: this.options.minimumViaSeparation
41276
+ }) || doesViaIntersectStitchingObstacle({
41277
+ center,
41278
+ radius: requiredObstacleRadius,
41279
+ obstacles: this.stitchingObstacles
41280
+ }) || !isViaAnnulusInsideShapeUnion({
41281
+ center,
41282
+ radius: requiredCopperRadius,
41283
+ shapes: fromLayerShapes
41284
+ }) || !isViaAnnulusInsideShapeUnion({
41285
+ center,
41286
+ radius: requiredCopperRadius,
41287
+ shapes: toLayerShapes
41288
+ })) {
41289
+ continue;
41290
+ }
41291
+ let pcbViaId = `via_stitch_via_${this.nextViaId++}`;
41292
+ while (this.existingPcbViaIds.has(pcbViaId)) {
41293
+ pcbViaId = `via_stitch_via_${this.nextViaId++}`;
41294
+ }
41295
+ const referencePour = context.fromLayerPours[0];
41296
+ const pcbVia = {
41297
+ type: "pcb_via",
41298
+ pcb_via_id: pcbViaId,
41299
+ x,
41300
+ y,
41301
+ hole_diameter: this.options.viaHoleDiameter,
41302
+ outer_diameter: this.options.viaOuterDiameter,
41303
+ layers: [fromLayer, toLayer],
41304
+ from_layer: fromLayer,
41305
+ to_layer: toLayer,
41306
+ source_net_id: context.sourceNetId,
41307
+ subcircuit_id: referencePour.subcircuit_id,
41308
+ pcb_group_id: referencePour.pcb_group_id,
41309
+ subcircuit_connectivity_map_key: context.sourceNet?.subcircuit_connectivity_map_key,
41310
+ is_tented: this.options.isTented
41311
+ };
41312
+ this.pcbVias.push(pcbVia);
41313
+ this.existingPcbViaIds.add(pcbViaId);
41314
+ this.occupiedVias.push({ center, radius: viaRadius });
41315
+ }
41316
+ }
41317
+ }
41318
+ getOutput() {
41319
+ return {
41320
+ processedCopperPourPairCount: this.copperPourPairContexts.length,
41321
+ pcbVias: this.pcbVias
41322
+ };
41323
+ }
41324
+ };
41325
+
41326
+ // lib/solvers.ts
40822
41327
  import { PackSolver2 } from "calculate-packing";
40823
41328
  var SOLVERS = {
40824
41329
  PackSolver2,
@@ -40838,7 +41343,8 @@ var SOLVERS = {
40838
41343
  CreateFdmEnclosureSolver,
40839
41344
  FanoutSolver,
40840
41345
  ImplicitCopperPourPipelineSolver,
40841
- SchematicTracePipelineSolver
41346
+ SchematicTracePipelineSolver,
41347
+ ViaStitchSolver
40842
41348
  };
40843
41349
 
40844
41350
  // lib/utils/autorouting/LocalCacheEngineCacheProvider.ts
@@ -50925,7 +51431,7 @@ function Group_getRoutingPhasePlans(group) {
50925
51431
  var package_default = {
50926
51432
  name: "@tscircuit/core",
50927
51433
  type: "module",
50928
- version: "0.0.1857",
51434
+ version: "0.0.1859",
50929
51435
  types: "dist/index.d.ts",
50930
51436
  main: "dist/index.js",
50931
51437
  module: "dist/index.js",
@@ -50983,6 +51489,7 @@ var package_default = {
50983
51489
  "@tscircuit/schematic-trace-solver": "^0.0.186",
50984
51490
  "@tscircuit/solver-utils": "^0.0.16",
50985
51491
  "@tscircuit/soup-util": "^0.0.41",
51492
+ "@tscircuit/via-stitch-solver": "github:tscircuit/via-stitch-solver#75653b6440e75584b052f03595afd34283ae7558",
50986
51493
  "@tscircuit/winding-breakout-point-solver": "github:tscircuit/winding-breakout-point-solver#202dbe9eb0088633b6fa094120dba6f2f41f8803",
50987
51494
  "@types/bun": "^1.2.16",
50988
51495
  "@types/debug": "^4.1.12",
@@ -51654,7 +52161,7 @@ function getAccumulatedPcbTracesWithStageOutputReplacements({
51654
52161
  // lib/components/primitive-components/Group/get-source-trace-id-for-routed-trace.ts
51655
52162
  import { distance as distance14, pointToSegmentDistance as pointToSegmentDistance3 } from "@tscircuit/math-utils";
51656
52163
  import { ConnectivityMap as ConnectivityMap5 } from "circuit-json-to-connectivity-map";
51657
- var POINT_EPSILON = 1e-6;
52164
+ var POINT_EPSILON2 = 1e-6;
51658
52165
  function isPointOnWireSegment({
51659
52166
  point: point6,
51660
52167
  segmentStart,
@@ -51663,7 +52170,7 @@ function isPointOnWireSegment({
51663
52170
  if (point6.layer && (segmentStart.layer !== point6.layer || segmentEnd.layer !== point6.layer)) {
51664
52171
  return false;
51665
52172
  }
51666
- return pointToSegmentDistance3(point6, segmentStart, segmentEnd) <= POINT_EPSILON;
52173
+ return pointToSegmentDistance3(point6, segmentStart, segmentEnd) <= POINT_EPSILON2;
51667
52174
  }
51668
52175
  function isPointInSmtPad({
51669
52176
  point: point6,
@@ -55449,6 +55956,8 @@ var IsolatedCircuit = class {
55449
55956
  pcbDisabled = false;
55450
55957
  pcbRoutingDisabled = false;
55451
55958
  _featureMspSchematicTraceRouting = true;
55959
+ /** Experimental automatic via stitching; opt in before rendering. */
55960
+ _featurePcbViaStitching = false;
55452
55961
  /**
55453
55962
  * The IsolatedCircuit name is usually set by the platform, it's not required but
55454
55963
  * if supplied can identify the circuit in certain effects, e.g. it is passed
@@ -55873,7 +56382,7 @@ import {
55873
56382
  // lib/components/primitive-components/CopperPour/utils/mark-trace-segments-inside-copper-pour.ts
55874
56383
  var EPSILON14 = 1e-9;
55875
56384
  var isWireRoutePoint = (routePoint) => routePoint.route_type === "wire";
55876
- var isPointOnSegment = (p, a, b) => {
56385
+ var isPointOnSegment2 = (p, a, b) => {
55877
56386
  const cross3 = (p.y - a.y) * (b.x - a.x) - (p.x - a.x) * (b.y - a.y);
55878
56387
  if (Math.abs(cross3) > EPSILON14) return false;
55879
56388
  const dot = (p.x - a.x) * (b.x - a.x) + (p.y - a.y) * (b.y - a.y);
@@ -55882,12 +56391,12 @@ var isPointOnSegment = (p, a, b) => {
55882
56391
  if (dot - squaredLength > EPSILON14) return false;
55883
56392
  return true;
55884
56393
  };
55885
- var isPointInRing = (point6, ring) => {
56394
+ var isPointInRing2 = (point6, ring) => {
55886
56395
  if (ring.length < 3) return false;
55887
56396
  let inside = false;
55888
56397
  let previous = ring[ring.length - 1];
55889
56398
  for (const current of ring) {
55890
- if (isPointOnSegment(point6, previous, current)) return true;
56399
+ if (isPointOnSegment2(point6, previous, current)) return true;
55891
56400
  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
56401
  if (intersects) inside = !inside;
55893
56402
  previous = current;
@@ -55910,10 +56419,10 @@ var isPointInBrepPour = (p, pour) => {
55910
56419
  x: v.x,
55911
56420
  y: v.y
55912
56421
  }));
55913
- if (!isPointInRing(p, outerRing)) return false;
56422
+ if (!isPointInRing2(p, outerRing)) return false;
55914
56423
  for (const innerRing of pour.brep_shape.inner_rings) {
55915
56424
  const points = innerRing.vertices.map((v) => ({ x: v.x, y: v.y }));
55916
- if (isPointInRing(p, points)) return false;
56425
+ if (isPointInRing2(p, points)) return false;
55917
56426
  }
55918
56427
  return true;
55919
56428
  };
@@ -56100,6 +56609,59 @@ function CopperPour_doInitialPcbCopperPourRender(copperPour) {
56100
56609
  });
56101
56610
  }
56102
56611
 
56612
+ // lib/components/primitive-components/CopperPour/CopperPour_doInitialPcbViaStitchRender.ts
56613
+ var renderViaStitchingForCopperPours = (copperPour) => {
56614
+ const subcircuit = copperPour.getSubcircuit();
56615
+ if (!subcircuit.root) return;
56616
+ const copperPours = subcircuit.selectAll("copperpour").filter(
56617
+ (candidateCopperPour) => candidateCopperPour.getSubcircuit() === subcircuit
56618
+ );
56619
+ if (copperPours[0] !== copperPour) return;
56620
+ const sourceNetIds = copperPours.flatMap((candidateCopperPour) => {
56621
+ const net = subcircuit.selectOne(
56622
+ candidateCopperPour._parsedProps.connectsTo
56623
+ );
56624
+ return net?.source_net_id ? [net.source_net_id] : [];
56625
+ });
56626
+ if (sourceNetIds.length === 0) return;
56627
+ const { db } = subcircuit.root;
56628
+ const pcbStyle = copperPour.getInheritedMergedProperty("pcbStyle");
56629
+ const { holeDiameter, padDiameter } = getViaDiameterDefaults(pcbStyle);
56630
+ const boardComponent = copperPour._getBoard();
56631
+ const pcbBoard = boardComponent?.pcb_board_id ? db.pcb_board.get(boardComponent.pcb_board_id) : void 0;
56632
+ const solverInput = {
56633
+ circuitJson: db.toArray(),
56634
+ options: {
56635
+ sourceNetIds: [...new Set(sourceNetIds)],
56636
+ viaHoleDiameter: pcbBoard?.min_via_hole_diameter ?? holeDiameter,
56637
+ viaOuterDiameter: pcbBoard?.min_via_pad_diameter ?? padDiameter
56638
+ }
56639
+ };
56640
+ const solver = new ViaStitchSolver(solverInput);
56641
+ subcircuit.root.emit("solver:started", {
56642
+ type: "solver:started",
56643
+ solverName: "ViaStitchSolver",
56644
+ solverParams: solverInput,
56645
+ solverConstructorArgs: [solverInput],
56646
+ componentName: subcircuit.getString()
56647
+ });
56648
+ solver.solve();
56649
+ if (solver.failed) {
56650
+ throw new Error(solver.error ?? "Via stitching solver failed");
56651
+ }
56652
+ for (const pcbVia of solver.getOutput().pcbVias) {
56653
+ const { pcb_via_id: _solverViaId, ...pcbViaInput } = pcbVia;
56654
+ db.pcb_via.insert(pcbViaInput);
56655
+ }
56656
+ };
56657
+ function CopperPour_doInitialPcbViaStitchRender(copperPour) {
56658
+ if (copperPour.root?.pcbDisabled || !copperPour.root?._featurePcbViaStitching)
56659
+ return;
56660
+ copperPour._queueAsyncEffect("PcbViaStitchRender", async () => {
56661
+ renderViaStitchingForCopperPours(copperPour);
56662
+ });
56663
+ }
56664
+
56103
56665
  // lib/components/primitive-components/CopperPour/CopperPour.ts
56104
56666
  var CopperPour = class extends PrimitiveComponent2 {
56105
56667
  isPcbPrimitive = true;
@@ -56120,6 +56682,9 @@ var CopperPour = class extends PrimitiveComponent2 {
56120
56682
  doInitialPcbCopperPourRender() {
56121
56683
  CopperPour_doInitialPcbCopperPourRender(this);
56122
56684
  }
56685
+ doInitialPcbViaStitchRender() {
56686
+ CopperPour_doInitialPcbViaStitchRender(this);
56687
+ }
56123
56688
  };
56124
56689
 
56125
56690
  // lib/components/normal-components/Board_doInitialPcbImplicitCopperPourRender.ts
@@ -60225,7 +60790,7 @@ var validateWindingBreakoutInput = (input) => {
60225
60790
  };
60226
60791
 
60227
60792
  // node_modules/@tscircuit/winding-breakout-point-solver/lib/solvers/GatePlacementSolver.ts
60228
- import { BaseSolver as BaseSolver3 } from "@tscircuit/solver-utils";
60793
+ import { BaseSolver as BaseSolver4 } from "@tscircuit/solver-utils";
60229
60794
 
60230
60795
  // node_modules/@tscircuit/winding-breakout-point-solver/lib/gate-placement/place-breakout-gates.ts
60231
60796
  var GEOMETRY_EPSILON = 1e-9;
@@ -60755,7 +61320,7 @@ var getSharedGateSlotCount = (points) => new Set(
60755
61320
  (point6) => `${point6.regionId}:${point6.x.toFixed(9)}:${point6.y.toFixed(9)}`
60756
61321
  )
60757
61322
  ).size;
60758
- var GatePlacementSolver = class extends BaseSolver3 {
61323
+ var GatePlacementSolver = class extends BaseSolver4 {
60759
61324
  constructor(params) {
60760
61325
  super();
60761
61326
  this.params = params;
@@ -60894,7 +61459,7 @@ var GatePlacementSolver = class extends BaseSolver3 {
60894
61459
  };
60895
61460
 
60896
61461
  // node_modules/@tscircuit/winding-breakout-point-solver/lib/solvers/ReferenceOrderingSolver.ts
60897
- import { BaseSolver as BaseSolver4 } from "@tscircuit/solver-utils";
61462
+ import { BaseSolver as BaseSolver5 } from "@tscircuit/solver-utils";
60898
61463
 
60899
61464
  // node_modules/@tscircuit/winding-breakout-point-solver/lib/ordering/get-natural-winding-order.ts
60900
61465
  var getNaturalWindingOrder = (region, connections) => connections.map((connection) => {
@@ -60961,7 +61526,7 @@ var getReferenceWindingOrder = (naturalOrder, atomicGroups, buses) => {
60961
61526
  };
60962
61527
 
60963
61528
  // node_modules/@tscircuit/winding-breakout-point-solver/lib/solvers/ReferenceOrderingSolver.ts
60964
- var ReferenceOrderingSolver = class extends BaseSolver4 {
61529
+ var ReferenceOrderingSolver = class extends BaseSolver5 {
60965
61530
  constructor(params) {
60966
61531
  super();
60967
61532
  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.1860",
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",