@tscircuit/core 0.0.1966 → 0.0.1968

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
@@ -358,6 +358,7 @@ interface DebugLogOutputEvent {
358
358
  }
359
359
 
360
360
  interface IIsolatedCircuit {
361
+ _hasRenderLifecycleListeners?: boolean;
361
362
  hasEventListener?(event: RootCircuitEventName): boolean;
362
363
  emit(event: RootCircuitEventName, ...args: any[]): void;
363
364
  on(event: RootCircuitEventName, listener: (...args: any[]) => void): void;
@@ -368,9 +369,9 @@ interface IIsolatedCircuit {
368
369
  interface IRootCircuit extends IIsolatedCircuit {
369
370
  }
370
371
 
371
- 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", "PcbFlexRender", "PcbAutoplaceBreakoutPoints", "PcbTraceHintRender", "PcbManualTraceRender", "PcbPlacementDesignRuleChecks", "PcbTraceRender", "PcbRouteNetIslands", "PcbImplicitCopperPourRender", "PcbCopperPourRender", "PcbViaStitchRender", "PcbCopperPourCleanup", "PcbDesignRuleChecks", "SilkscreenOverlapAdjustment", "CadModelRender", "PartsEngineRender", "PartOrientationAnalysis", "SupplierFootprintMismatchWarning", "SimulationSpiceEngineRender"];
372
+ 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", "PcbFlexRender", "PcbAutoplaceBreakoutPoints", "PcbTraceHintRender", "PcbManualTraceRender", "PcbPlacementDesignRuleChecks", "PcbTraceRender", "PcbRouteNetIslands", "PcbCopperPourRender", "PcbViaStitchRender", "PcbCopperPourCleanup", "PcbDesignRuleChecks", "SilkscreenOverlapAdjustment", "CadModelRender", "PartsEngineRender", "PartOrientationAnalysis", "SupplierFootprintMismatchWarning", "SimulationSpiceEngineRender"];
372
373
  type RenderPhase = (typeof orderedRenderPhases)[number];
373
- 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" | "PcbFlexRender" | "PcbAutoplaceBreakoutPoints" | "PcbTraceHintRender" | "PcbManualTraceRender" | "PcbPlacementDesignRuleChecks" | "PcbTraceRender" | "PcbRouteNetIslands" | "PcbImplicitCopperPourRender" | "PcbCopperPourRender" | "PcbViaStitchRender" | "PcbCopperPourCleanup" | "PcbDesignRuleChecks" | "SilkscreenOverlapAdjustment" | "CadModelRender" | "PartsEngineRender" | "PartOrientationAnalysis" | "SupplierFootprintMismatchWarning" | "SimulationSpiceEngineRender", number>;
374
+ 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" | "PcbFlexRender" | "PcbAutoplaceBreakoutPoints" | "PcbTraceHintRender" | "PcbManualTraceRender" | "PcbPlacementDesignRuleChecks" | "PcbTraceRender" | "PcbRouteNetIslands" | "PcbCopperPourRender" | "PcbViaStitchRender" | "PcbCopperPourCleanup" | "PcbDesignRuleChecks" | "SilkscreenOverlapAdjustment" | "CadModelRender" | "PartsEngineRender" | "PartOrientationAnalysis" | "SupplierFootprintMismatchWarning" | "SimulationSpiceEngineRender", number>;
374
375
  type RenderPhaseFn<K extends RenderPhase = RenderPhase> = `doInitial${K}` | `update${K}` | `remove${K}`;
375
376
  type RenderPhaseStates = Record<RenderPhase, {
376
377
  initialized: boolean;
@@ -395,7 +396,10 @@ type IRenderable = RenderPhaseFunctions & {
395
396
  runRenderCycle(): void;
396
397
  };
397
398
  declare abstract class Renderable implements IRenderable {
398
- renderPhaseStates: RenderPhaseStates;
399
+ private _phaseStatesByName?;
400
+ private readonly _phaseStatesByIndex;
401
+ get renderPhaseStates(): RenderPhaseStates;
402
+ set renderPhaseStates(states: RenderPhaseStates);
399
403
  shouldBeRemoved: boolean;
400
404
  children: IRenderable[];
401
405
  /** PCB-only SMTPads, PlatedHoles, Holes, Silkscreen elements etc. */
@@ -595,6 +599,7 @@ declare class IsolatedCircuit {
595
599
  selectOne(selector: string, opts?: {
596
600
  type?: "component" | "port";
597
601
  }): PrimitiveComponent | null;
602
+ _hasRenderLifecycleListeners: boolean;
598
603
  _eventListeners: Record<RootCircuitEventName, Array<(...args: any[]) => void>>;
599
604
  emit(event: RootCircuitEventName, ...args: any[]): void;
600
605
  hasEventListener(event: RootCircuitEventName): boolean;
@@ -6246,7 +6251,6 @@ declare class Board extends Group<typeof boardProps> implements BoardI, Subcircu
6246
6251
  removePcbComponentRender(): void;
6247
6252
  doInitialPcbDesignRuleChecks(): void;
6248
6253
  doInitialPcbPlacementDesignRuleChecks(): void;
6249
- doInitialPcbImplicitCopperPourRender(): void;
6250
6254
  _generatedStitchingViaIds: Set<string>;
6251
6255
  doInitialPcbCopperPourCleanup(): void;
6252
6256
  updatePcbDesignRuleChecks(): void;
package/dist/index.js CHANGED
@@ -484,7 +484,6 @@ var orderedRenderPhases = [
484
484
  "PcbPlacementDesignRuleChecks",
485
485
  "PcbTraceRender",
486
486
  "PcbRouteNetIslands",
487
- "PcbImplicitCopperPourRender",
488
487
  "PcbCopperPourRender",
489
488
  "PcbViaStitchRender",
490
489
  "PcbCopperPourCleanup",
@@ -535,14 +534,6 @@ var asyncPhaseDependencies = {
535
534
  PcbTraceHintRender: ["PcbFootprintStringRender", "FetchPartFootprint"],
536
535
  PcbManualTraceRender: ["PcbFootprintStringRender", "FetchPartFootprint"],
537
536
  PcbCopperPourRender: [
538
- "PcbFootprintStringRender",
539
- "FetchPartFootprint",
540
- "PcbPlacementDesignRuleChecks",
541
- "PcbTraceRender",
542
- "PcbRouteNetIslands",
543
- "PcbImplicitCopperPourRender"
544
- ],
545
- PcbImplicitCopperPourRender: [
546
537
  "PcbFootprintStringRender",
547
538
  "FetchPartFootprint",
548
539
  "PcbPlacementDesignRuleChecks",
@@ -555,7 +546,6 @@ var asyncPhaseDependencies = {
555
546
  "PcbPlacementDesignRuleChecks",
556
547
  "PcbTraceRender",
557
548
  "PcbRouteNetIslands",
558
- "PcbImplicitCopperPourRender",
559
549
  "PcbCopperPourRender"
560
550
  ],
561
551
  PcbPlacementDesignRuleChecks: [
@@ -568,7 +558,6 @@ var asyncPhaseDependencies = {
568
558
  "PcbPlacementDesignRuleChecks",
569
559
  "PcbTraceRender",
570
560
  "PcbRouteNetIslands",
571
- "PcbImplicitCopperPourRender",
572
561
  "PcbCopperPourRender",
573
562
  "PcbViaStitchRender"
574
563
  ],
@@ -583,7 +572,6 @@ var asyncPhaseDependencies = {
583
572
  "FetchPartFootprint",
584
573
  "PcbPlacementDesignRuleChecks",
585
574
  "PcbTraceRender",
586
- "PcbImplicitCopperPourRender",
587
575
  "PcbCopperPourRender",
588
576
  "PcbViaStitchRender",
589
577
  "PcbCopperPourCleanup"
@@ -622,7 +610,21 @@ var asyncPhaseDependencies = {
622
610
  var globalRenderCounter = 0;
623
611
  var globalAsyncEffectCounter = 0;
624
612
  var Renderable = class _Renderable {
625
- renderPhaseStates;
613
+ _phaseStatesByName;
614
+ _phaseStatesByIndex;
615
+ // Build the named map once, sharing the state objects used by the render loop.
616
+ // Once exposed, use the map so callers can also replace individual entries.
617
+ get renderPhaseStates() {
618
+ return this._phaseStatesByName ??= Object.fromEntries(
619
+ orderedRenderPhases.map((phase, index) => [
620
+ phase,
621
+ this._phaseStatesByIndex[index]
622
+ ])
623
+ );
624
+ }
625
+ set renderPhaseStates(states) {
626
+ this._phaseStatesByName = states;
627
+ }
626
628
  shouldBeRemoved = false;
627
629
  children;
628
630
  /** PCB-only SMTPads, PlatedHoles, Holes, Silkscreen elements etc. */
@@ -637,19 +639,19 @@ var Renderable = class _Renderable {
637
639
  constructor(props) {
638
640
  this._renderId = `${globalRenderCounter++}`;
639
641
  this.children = [];
640
- this.renderPhaseStates = {};
641
- for (const phase of orderedRenderPhases) {
642
- this.renderPhaseStates[phase] = {
642
+ this._phaseStatesByIndex = Array.from(
643
+ { length: orderedRenderPhases.length },
644
+ () => ({
643
645
  initialized: false,
644
646
  dirty: false
645
- };
646
- }
647
+ })
648
+ );
647
649
  }
648
650
  _markDirty(phase) {
649
- this.renderPhaseStates[phase].dirty = true;
650
651
  const phaseIndex = renderPhaseIndexMap.get(phase);
651
- for (let i = phaseIndex + 1; i < orderedRenderPhases.length; i++) {
652
- this.renderPhaseStates[orderedRenderPhases[i]].dirty = true;
652
+ for (let i = phaseIndex; i < orderedRenderPhases.length; i++) {
653
+ const state = this._phaseStatesByName?.[orderedRenderPhases[i]] ?? this._phaseStatesByIndex[i];
654
+ state.dirty = true;
653
655
  }
654
656
  if (this.parent?._markDirty) {
655
657
  this.parent._markDirty(phase);
@@ -705,8 +707,9 @@ ${error.stack}`
705
707
  });
706
708
  }
707
709
  _emitRenderLifecycleEvent(phase, startOrEnd) {
708
- const granular_event_type = `renderable:renderLifecycle:${phase}:${startOrEnd}`;
709
710
  const root = this._getRootCircuit();
711
+ if (root?._hasRenderLifecycleListeners === false && !debug.enabled) return;
712
+ const granular_event_type = `renderable:renderLifecycle:${phase}:${startOrEnd}`;
710
713
  const hasListeners = root && (!root.hasEventListener || root.hasEventListener(granular_event_type) || root.hasEventListener("renderable:renderLifecycle:anyEvent"));
711
714
  if (!debug.enabled && !hasListeners) return;
712
715
  const componentDisplayName = this.getString();
@@ -786,9 +789,9 @@ ${error.stack}`
786
789
  */
787
790
  runRenderPhase(phase) {
788
791
  this._currentRenderPhase = phase;
789
- const phaseState = this.renderPhaseStates[phase];
790
- const isInitialized = phaseState.initialized;
791
- const isDirty = phaseState.dirty;
792
+ const phaseIndex = renderPhaseIndexMap.get(phase);
793
+ const phaseState = this._phaseStatesByName?.[phase] ?? this._phaseStatesByIndex[phaseIndex];
794
+ const { initialized: isInitialized, dirty: isDirty } = phaseState;
792
795
  if (!isInitialized && this.shouldBeRemoved) return;
793
796
  if (this.shouldBeRemoved && isInitialized) {
794
797
  this._emitRenderLifecycleEvent(phase, "start");
@@ -798,10 +801,12 @@ ${error.stack}`
798
801
  this._emitRenderLifecycleEvent(phase, "end");
799
802
  return;
800
803
  }
801
- const prevPhaseIndex = renderPhaseIndexMap.get(phase) - 1;
802
- if (prevPhaseIndex >= 0) {
804
+ const prevPhaseIndex = phaseIndex - 1;
805
+ if (this._asyncEffects.length > 0 && prevPhaseIndex >= 0) {
803
806
  const prevPhase = orderedRenderPhases[prevPhaseIndex];
804
- const hasIncompleteEffects = this._asyncEffects.filter((e) => e.phase === prevPhase).some((e) => !e.complete);
807
+ const hasIncompleteEffects = this._asyncEffects.some(
808
+ (e) => e.phase === prevPhase && !e.complete
809
+ );
805
810
  if (hasIncompleteEffects) return;
806
811
  }
807
812
  const deps = asyncPhaseDependencies[phase] || [];
@@ -829,7 +834,7 @@ ${error.stack}`
829
834
  }
830
835
  runRenderPhaseForChildren(phase) {
831
836
  for (const child of this.children) {
832
- if ("_isIsolatedSubcircuit" in this && this._isIsolatedSubcircuit && "doInitialRenderIsolatedSubcircuits" in this && phase === "RenderIsolatedSubcircuits") {
837
+ if (phase === "RenderIsolatedSubcircuits" && "_isIsolatedSubcircuit" in this && this._isIsolatedSubcircuit && "doInitialRenderIsolatedSubcircuits" in this) {
833
838
  continue;
834
839
  }
835
840
  child.runRenderPhaseForChildren(phase);
@@ -63783,7 +63788,7 @@ function Group_getRoutingPhasePlans(group) {
63783
63788
  var package_default = {
63784
63789
  name: "@tscircuit/core",
63785
63790
  type: "module",
63786
- version: "0.0.1965",
63791
+ version: "0.0.1967",
63787
63792
  types: "dist/index.d.ts",
63788
63793
  main: "dist/index.js",
63789
63794
  module: "dist/index.js",
@@ -68649,6 +68654,7 @@ var IsolatedCircuit = class {
68649
68654
  this._guessRootComponent();
68650
68655
  return this.firstChild?.selectOne(selector, opts) ?? null;
68651
68656
  }
68657
+ _hasRenderLifecycleListeners = false;
68652
68658
  _eventListeners = {};
68653
68659
  emit(event, ...args) {
68654
68660
  if (event === "asyncEffect:start") {
@@ -68669,12 +68675,22 @@ var IsolatedCircuit = class {
68669
68675
  this._eventListeners[event] = [];
68670
68676
  }
68671
68677
  this._eventListeners[event].push(listener);
68678
+ if (event.startsWith("renderable:renderLifecycle:")) {
68679
+ this._hasRenderLifecycleListeners = true;
68680
+ }
68672
68681
  }
68673
68682
  removeListener(event, listener) {
68674
68683
  if (!this._eventListeners[event]) return;
68675
68684
  this._eventListeners[event] = this._eventListeners[event].filter(
68676
68685
  (l) => l !== listener
68677
68686
  );
68687
+ if (event.startsWith("renderable:renderLifecycle:")) {
68688
+ this._hasRenderLifecycleListeners = Object.entries(
68689
+ this._eventListeners
68690
+ ).some(
68691
+ ([eventName, listeners]) => eventName.startsWith("renderable:renderLifecycle:") && listeners.length > 0
68692
+ );
68693
+ }
68678
68694
  }
68679
68695
  enableDebug(debug13) {
68680
68696
  if (typeof debug13 === "string") {
@@ -68875,382 +68891,6 @@ function Subcircuit_getSubcircuitPropHash(subcircuit) {
68875
68891
  return computeHash(hashableData);
68876
68892
  }
68877
68893
 
68878
- // lib/components/primitive-components/CopperPour/CopperPour.ts
68879
- import { copperPourProps } from "@tscircuit/props";
68880
-
68881
- // lib/components/primitive-components/CopperPour/CopperPour_doInitialPcbCopperPourRender.ts
68882
- import {
68883
- CopperPourPipelineSolver as CopperPourPipelineSolver2,
68884
- convertCircuitJsonToInputProblem,
68885
- initializeManifoldGeometry
68886
- } from "@tscircuit/copper-pour-solver";
68887
-
68888
- // lib/components/primitive-components/CopperPour/utils/mark-trace-segments-inside-copper-pour.ts
68889
- var EPSILON24 = 1e-9;
68890
- var isWireRoutePoint = (routePoint) => routePoint.route_type === "wire";
68891
- var isPointOnSegment2 = (p, a, b) => {
68892
- const cross4 = (p.y - a.y) * (b.x - a.x) - (p.x - a.x) * (b.y - a.y);
68893
- if (Math.abs(cross4) > EPSILON24) return false;
68894
- const dot = (p.x - a.x) * (b.x - a.x) + (p.y - a.y) * (b.y - a.y);
68895
- if (dot < -EPSILON24) return false;
68896
- const squaredLength = (b.x - a.x) ** 2 + (b.y - a.y) ** 2;
68897
- if (dot - squaredLength > EPSILON24) return false;
68898
- return true;
68899
- };
68900
- var isPointInRing2 = (point6, ring) => {
68901
- if (ring.length < 3) return false;
68902
- let inside2 = false;
68903
- let previous = ring[ring.length - 1];
68904
- for (const current of ring) {
68905
- if (isPointOnSegment2(point6, previous, current)) return true;
68906
- 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;
68907
- if (intersects) inside2 = !inside2;
68908
- previous = current;
68909
- }
68910
- return inside2;
68911
- };
68912
- var isPointInRectPour = (p, pour) => {
68913
- const { center, width, height } = pour;
68914
- const rotationRad = (pour.rotation ?? 0) * Math.PI / 180;
68915
- const cosR = Math.cos(-rotationRad);
68916
- const sinR = Math.sin(-rotationRad);
68917
- const dx = p.x - center.x;
68918
- const dy = p.y - center.y;
68919
- const localX = dx * cosR - dy * sinR;
68920
- const localY = dx * sinR + dy * cosR;
68921
- return Math.abs(localX) <= width / 2 + EPSILON24 && Math.abs(localY) <= height / 2 + EPSILON24;
68922
- };
68923
- var isPointInBrepPour = (p, pour) => {
68924
- const outerRing = pour.brep_shape.outer_ring.vertices.map((v) => ({
68925
- x: v.x,
68926
- y: v.y
68927
- }));
68928
- if (!isPointInRing2(p, outerRing)) return false;
68929
- for (const innerRing of pour.brep_shape.inner_rings) {
68930
- const points = innerRing.vertices.map((v) => ({ x: v.x, y: v.y }));
68931
- if (isPointInRing2(p, points)) return false;
68932
- }
68933
- return true;
68934
- };
68935
- var isPointInCopperPour = (point6, pour) => {
68936
- if (pour.shape === "rect") {
68937
- return isPointInRectPour(point6, pour);
68938
- }
68939
- if (pour.shape === "brep") {
68940
- return isPointInBrepPour(point6, pour);
68941
- }
68942
- return false;
68943
- };
68944
- var isTraceConnectedToSourceNet = (trace, sourceNetId, sourceTraceById) => {
68945
- if (trace.source_trace_id === sourceNetId) return true;
68946
- if (!trace.source_trace_id) return false;
68947
- const sourceTrace = sourceTraceById.get(trace.source_trace_id);
68948
- if (!sourceTrace) return false;
68949
- return sourceTrace.connected_source_net_ids.includes(sourceNetId);
68950
- };
68951
- var isSegmentFullyInsideCopperPour = (start, end, pour) => {
68952
- const dx = end.x - start.x;
68953
- const dy = end.y - start.y;
68954
- const length8 = Math.hypot(dx, dy);
68955
- if (length8 <= EPSILON24) return false;
68956
- const samples = [0, 0.25, 0.5, 0.75, 1];
68957
- return samples.every(
68958
- (t) => isPointInCopperPour(
68959
- {
68960
- x: start.x + dx * t,
68961
- y: start.y + dy * t
68962
- },
68963
- pour
68964
- )
68965
- );
68966
- };
68967
- var markTraceSegmentsInsideCopperPour = ({
68968
- db,
68969
- copperPour
68970
- }) => {
68971
- if (!copperPour.source_net_id) return;
68972
- const sourceTraceById = new Map(
68973
- db.source_trace.list().map((sourceTrace) => [sourceTrace.source_trace_id, sourceTrace])
68974
- );
68975
- for (const trace of db.pcb_trace.list()) {
68976
- if (!isTraceConnectedToSourceNet(
68977
- trace,
68978
- copperPour.source_net_id,
68979
- sourceTraceById
68980
- )) {
68981
- continue;
68982
- }
68983
- let routeChanged = false;
68984
- const nextRoute = trace.route.map((routePoint) => ({ ...routePoint }));
68985
- for (let i = 0; i < nextRoute.length - 1; i++) {
68986
- const fromRoutePoint = nextRoute[i];
68987
- const toRoutePoint = nextRoute[i + 1];
68988
- if (!fromRoutePoint || !toRoutePoint) continue;
68989
- if (!isWireRoutePoint(fromRoutePoint) || !isWireRoutePoint(toRoutePoint))
68990
- continue;
68991
- if (fromRoutePoint.layer !== copperPour.layer || toRoutePoint.layer !== copperPour.layer)
68992
- continue;
68993
- if (isSegmentFullyInsideCopperPour(
68994
- { x: fromRoutePoint.x, y: fromRoutePoint.y },
68995
- { x: toRoutePoint.x, y: toRoutePoint.y },
68996
- copperPour
68997
- )) {
68998
- fromRoutePoint.is_inside_copper_pour = true;
68999
- fromRoutePoint.copper_pour_id = copperPour.pcb_copper_pour_id;
69000
- toRoutePoint.is_inside_copper_pour = true;
69001
- toRoutePoint.copper_pour_id = copperPour.pcb_copper_pour_id;
69002
- routeChanged = true;
69003
- }
69004
- }
69005
- if (routeChanged) {
69006
- db.pcb_trace.update(trace.pcb_trace_id, { route: nextRoute });
69007
- }
69008
- }
69009
- };
69010
-
69011
- // lib/components/primitive-components/CopperPour/CopperPour_doInitialPcbCopperPourRender.ts
69012
- var pendingCopperPourRenders = /* @__PURE__ */ new WeakMap();
69013
- var DEFAULT_THERMAL_RELIEF_SPOKE_WIDTH_MM = 0.3;
69014
- var renderAllCopperPoursForSubcircuit = async (subcircuit) => {
69015
- if (!subcircuit.root) return;
69016
- const { db } = subcircuit.root;
69017
- const copperPours = subcircuit.selectAll("copperpour").filter((copperPour) => copperPour.getSubcircuit() === subcircuit);
69018
- const resolvedCopperPours = [];
69019
- for (const copperPour of copperPours) {
69020
- const { _parsedProps: props } = copperPour;
69021
- const net = subcircuit.selectOne(props.connectsTo);
69022
- const sourceNetId = net?.source_net_id;
69023
- if (!sourceNetId) {
69024
- copperPour.renderError(
69025
- `Net "${props.connectsTo}" not found for copper pour`
69026
- );
69027
- continue;
69028
- }
69029
- resolvedCopperPours.push({ copperPour, sourceNetId });
69030
- }
69031
- if (resolvedCopperPours.length === 0) return;
69032
- const circuitJson = db.toArray();
69033
- const boardComponent = subcircuit._getBoard();
69034
- const pcbBoard = boardComponent?.pcb_board_id ? db.pcb_board.get(boardComponent.pcb_board_id) : void 0;
69035
- let resolvedPcbBoardOutline = pcbBoard?.outline?.length ? pcbBoard.outline : void 0;
69036
- if (!resolvedPcbBoardOutline && pcbBoard?.width !== void 0 && pcbBoard.height !== void 0) {
69037
- const { center, width, height } = pcbBoard;
69038
- resolvedPcbBoardOutline = [
69039
- { x: center.x - width / 2, y: center.y - height / 2 },
69040
- { x: center.x + width / 2, y: center.y - height / 2 },
69041
- { x: center.x + width / 2, y: center.y + height / 2 },
69042
- { x: center.x - width / 2, y: center.y + height / 2 }
69043
- ];
69044
- }
69045
- const inputProblem = convertCircuitJsonToInputProblem(
69046
- circuitJson,
69047
- resolvedCopperPours.map(({ copperPour, sourceNetId }) => {
69048
- const { _parsedProps: props } = copperPour;
69049
- const clearance = props.clearance ?? 0.2;
69050
- return {
69051
- layer: props.layer,
69052
- subcircuit_id: subcircuit.subcircuit_id ?? void 0,
69053
- source_net_id: sourceNetId,
69054
- pad_margin: props.padMargin ?? clearance,
69055
- trace_margin: props.traceMargin ?? clearance,
69056
- pour_margin: clearance,
69057
- board_edge_margin: props.boardEdgeMargin ?? clearance,
69058
- board_edge_outline: copperPour._isImplicitCopperPour ? resolvedPcbBoardOutline : void 0,
69059
- cutout_margin: props.cutoutMargin ?? clearance,
69060
- ...props.useThermalReliefs ? {
69061
- use_thermal_reliefs: true,
69062
- thermal_relief_spoke_width: DEFAULT_THERMAL_RELIEF_SPOKE_WIDTH_MM
69063
- } : {},
69064
- outline: props.outline ?? resolvedPcbBoardOutline
69065
- };
69066
- })
69067
- );
69068
- await initializeManifoldGeometry();
69069
- const solver = new CopperPourPipelineSolver2(inputProblem);
69070
- subcircuit.root.emit("solver:started", {
69071
- type: "solver:started",
69072
- solverName: "CopperPourPipelineSolver",
69073
- solverParams: inputProblem,
69074
- solverConstructorArgs: [inputProblem],
69075
- componentName: subcircuit.getString()
69076
- });
69077
- const { brep_shapes_by_region } = solver.getOutput();
69078
- for (const [
69079
- regionIndex,
69080
- { copperPour, sourceNetId }
69081
- ] of resolvedCopperPours.entries()) {
69082
- const { _parsedProps: props } = copperPour;
69083
- const coveredWithSolderMask = props.coveredWithSolderMask ?? false;
69084
- for (const brepShape of brep_shapes_by_region[regionIndex] ?? []) {
69085
- const insertedPour = db.pcb_copper_pour.insert({
69086
- shape: "brep",
69087
- layer: props.layer,
69088
- brep_shape: brepShape,
69089
- source_net_id: sourceNetId,
69090
- subcircuit_id: subcircuit.subcircuit_id ?? void 0,
69091
- covered_with_solder_mask: coveredWithSolderMask
69092
- });
69093
- markTraceSegmentsInsideCopperPour({
69094
- db,
69095
- copperPour: insertedPour
69096
- });
69097
- }
69098
- }
69099
- };
69100
- function CopperPour_doInitialPcbCopperPourRender(copperPour) {
69101
- if (copperPour.root?.pcbDisabled) return;
69102
- copperPour._queueAsyncEffect("PcbCopperPourRender", async () => {
69103
- const subcircuit = copperPour.getSubcircuit();
69104
- const pendingRender = pendingCopperPourRenders.get(subcircuit);
69105
- if (pendingRender) {
69106
- await pendingRender;
69107
- return;
69108
- }
69109
- const renderPromise = renderAllCopperPoursForSubcircuit(subcircuit);
69110
- pendingCopperPourRenders.set(subcircuit, renderPromise);
69111
- try {
69112
- await renderPromise;
69113
- } finally {
69114
- pendingCopperPourRenders.delete(subcircuit);
69115
- }
69116
- });
69117
- }
69118
-
69119
- // lib/components/primitive-components/CopperPour/CopperPour_doInitialPcbViaStitchRender.ts
69120
- import { pcb_via as pcb_via3 } from "circuit-json";
69121
- var renderViaStitchingForCopperPours = (copperPour) => {
69122
- const subcircuit = copperPour.getSubcircuit();
69123
- if (!subcircuit.root) return;
69124
- const copperPours = subcircuit.selectAll("copperpour").filter(
69125
- (candidateCopperPour) => candidateCopperPour.getSubcircuit() === subcircuit
69126
- );
69127
- if (copperPours[0] !== copperPour) return;
69128
- const sourceNetIds = copperPours.flatMap((candidateCopperPour) => {
69129
- const net = subcircuit.selectOne(
69130
- candidateCopperPour._parsedProps.connectsTo
69131
- );
69132
- return net?.source_net_id ? [net.source_net_id] : [];
69133
- });
69134
- if (sourceNetIds.length === 0) return;
69135
- const { db } = subcircuit.root;
69136
- const pcbStyle = copperPour.getInheritedMergedProperty("pcbStyle");
69137
- const { holeDiameter, padDiameter } = getViaDiameterDefaults(pcbStyle);
69138
- const boardComponent = copperPour._getBoard();
69139
- const pcbBoard = boardComponent?.pcb_board_id ? db.pcb_board.get(boardComponent.pcb_board_id) : void 0;
69140
- const solverInput = {
69141
- circuitJson: db.toArray(),
69142
- options: {
69143
- sourceNetIds: [...new Set(sourceNetIds)],
69144
- viaHoleDiameter: pcbBoard?.min_via_hole_diameter ?? holeDiameter,
69145
- viaOuterDiameter: pcbBoard?.min_via_pad_diameter ?? padDiameter,
69146
- viaStitchPitch: boardComponent?._parsedProps.viaStitchPitch
69147
- }
69148
- };
69149
- const solver = new ViaStitchSolver(solverInput);
69150
- subcircuit.root.emit("solver:started", {
69151
- type: "solver:started",
69152
- solverName: "ViaStitchSolver",
69153
- solverParams: solverInput,
69154
- solverConstructorArgs: [solverInput],
69155
- componentName: subcircuit.getString()
69156
- });
69157
- solver.solve();
69158
- if (solver.failed) {
69159
- throw new Error(solver.error ?? "Via stitching solver failed");
69160
- }
69161
- for (const pcbVia of solver.getOutput().pcbVias) {
69162
- const { pcb_via_id: _solverViaId, ...pcbViaInput } = pcb_via3.parse(pcbVia);
69163
- const insertedVia = db.pcb_via.insert({
69164
- ...pcbViaInput,
69165
- tented_on_top: void 0,
69166
- tented_on_bottom: void 0
69167
- });
69168
- boardComponent?._generatedStitchingViaIds?.add(insertedVia.pcb_via_id);
69169
- }
69170
- };
69171
- function CopperPour_doInitialPcbViaStitchRender(copperPour) {
69172
- if (copperPour.root?.pcbDisabled || !copperPour.root?._featurePcbViaStitching)
69173
- return;
69174
- if (!copperPour._getBoard()?._parsedProps.enableViaStitching) return;
69175
- copperPour._queueAsyncEffect("PcbViaStitchRender", async () => {
69176
- renderViaStitchingForCopperPours(copperPour);
69177
- });
69178
- }
69179
-
69180
- // lib/components/primitive-components/CopperPour/CopperPour.ts
69181
- var CopperPour = class extends PrimitiveComponent2 {
69182
- isPcbPrimitive = true;
69183
- _isImplicitCopperPour = false;
69184
- get config() {
69185
- return {
69186
- componentName: "CopperPour",
69187
- zodProps: copperPourProps
69188
- };
69189
- }
69190
- getPcbSize() {
69191
- return { width: 0, height: 0 };
69192
- }
69193
- doInitialCreateNetsFromProps() {
69194
- const { _parsedProps: props } = this;
69195
- createNetsFromProps(this, [props.connectsTo]);
69196
- }
69197
- doInitialPcbCopperPourRender() {
69198
- CopperPour_doInitialPcbCopperPourRender(this);
69199
- }
69200
- doInitialPcbViaStitchRender() {
69201
- CopperPour_doInitialPcbViaStitchRender(this);
69202
- }
69203
- };
69204
-
69205
- // lib/components/normal-components/Board_doInitialPcbImplicitCopperPourRender.ts
69206
- var Board_doInitialPcbImplicitCopperPourRender = (board) => {
69207
- const { root } = board;
69208
- if (!root || root.pcbDisabled) return;
69209
- if (!board._parsedProps.automaticPoursEnabled) return;
69210
- if (root.pcbRoutingDisabled || board.getInheritedProperty("routingDisabled"))
69211
- return;
69212
- const { db } = root;
69213
- const circuitJson = db.subtree({ subcircuit_id: board.subcircuit_id }).toArray();
69214
- const hasPowerNet = circuitJson.some(
69215
- (element) => element.type === "source_net" && (element.is_power || element.is_ground || element.is_positive_voltage_source)
69216
- );
69217
- if (!hasPowerNet) return;
69218
- const inputProblem = {
69219
- circuitJson,
69220
- layers: [...board.allLayers]
69221
- };
69222
- const solver = new ImplicitCopperPourPipelineSolver(inputProblem);
69223
- const solverConstructorArgs = solver.getConstructorParams();
69224
- root.emit("solver:started", {
69225
- type: "solver:started",
69226
- solverName: "ImplicitCopperPourPipelineSolver",
69227
- solverParams: solverConstructorArgs[0],
69228
- solverConstructorArgs,
69229
- componentName: board.getString()
69230
- });
69231
- solver.solve();
69232
- const boardNets = board.selectAll("net");
69233
- for (const implicitRegion of solver.getOutput()) {
69234
- if (implicitRegion.shape !== "polygon") continue;
69235
- const owningNet = boardNets.find(
69236
- (net) => net.source_net_id === implicitRegion.source_net_id
69237
- );
69238
- if (!owningNet) {
69239
- throw new Error(
69240
- `Unable to find the power net for implicit copper region ${implicitRegion.pcb_copper_pour_id}`
69241
- );
69242
- }
69243
- const copperPour = new CopperPour({
69244
- layer: implicitRegion.layer,
69245
- connectsTo: owningNet.getPortSelector(),
69246
- outline: implicitRegion.points,
69247
- coveredWithSolderMask: implicitRegion.covered_with_solder_mask
69248
- });
69249
- copperPour._isImplicitCopperPour = true;
69250
- owningNet.getSubcircuit().add(copperPour);
69251
- }
69252
- };
69253
-
69254
68894
  // lib/utils/copper-pour-connectivity/find-floating-copper.ts
69255
68895
  import {
69256
68896
  getFullConnectivityMapFromCircuitJson as getFullConnectivityMapFromCircuitJson5
@@ -70084,9 +69724,6 @@ var Board = class extends Group5 {
70084
69724
  doInitialPcbPlacementDesignRuleChecks() {
70085
69725
  Board_doInitialPcbPlacementDesignRuleChecks(this);
70086
69726
  }
70087
- doInitialPcbImplicitCopperPourRender() {
70088
- Board_doInitialPcbImplicitCopperPourRender(this);
70089
- }
70090
69727
  _generatedStitchingViaIds = /* @__PURE__ */ new Set();
70091
69728
  doInitialPcbCopperPourCleanup() {
70092
69729
  Board_doInitialPcbCopperPourCleanup(this);
@@ -75725,6 +75362,333 @@ var Fiducial = class extends PrimitiveComponent2 {
75725
75362
  }
75726
75363
  };
75727
75364
 
75365
+ // lib/components/primitive-components/CopperPour/CopperPour.ts
75366
+ import { copperPourProps } from "@tscircuit/props";
75367
+
75368
+ // lib/components/primitive-components/CopperPour/CopperPour_doInitialPcbCopperPourRender.ts
75369
+ import {
75370
+ CopperPourPipelineSolver as CopperPourPipelineSolver2,
75371
+ convertCircuitJsonToInputProblem,
75372
+ initializeManifoldGeometry
75373
+ } from "@tscircuit/copper-pour-solver";
75374
+
75375
+ // lib/components/primitive-components/CopperPour/utils/mark-trace-segments-inside-copper-pour.ts
75376
+ var EPSILON24 = 1e-9;
75377
+ var isWireRoutePoint = (routePoint) => routePoint.route_type === "wire";
75378
+ var isPointOnSegment2 = (p, a, b) => {
75379
+ const cross4 = (p.y - a.y) * (b.x - a.x) - (p.x - a.x) * (b.y - a.y);
75380
+ if (Math.abs(cross4) > EPSILON24) return false;
75381
+ const dot = (p.x - a.x) * (b.x - a.x) + (p.y - a.y) * (b.y - a.y);
75382
+ if (dot < -EPSILON24) return false;
75383
+ const squaredLength = (b.x - a.x) ** 2 + (b.y - a.y) ** 2;
75384
+ if (dot - squaredLength > EPSILON24) return false;
75385
+ return true;
75386
+ };
75387
+ var isPointInRing2 = (point6, ring) => {
75388
+ if (ring.length < 3) return false;
75389
+ let inside2 = false;
75390
+ let previous = ring[ring.length - 1];
75391
+ for (const current of ring) {
75392
+ if (isPointOnSegment2(point6, previous, current)) return true;
75393
+ 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;
75394
+ if (intersects) inside2 = !inside2;
75395
+ previous = current;
75396
+ }
75397
+ return inside2;
75398
+ };
75399
+ var isPointInRectPour = (p, pour) => {
75400
+ const { center, width, height } = pour;
75401
+ const rotationRad = (pour.rotation ?? 0) * Math.PI / 180;
75402
+ const cosR = Math.cos(-rotationRad);
75403
+ const sinR = Math.sin(-rotationRad);
75404
+ const dx = p.x - center.x;
75405
+ const dy = p.y - center.y;
75406
+ const localX = dx * cosR - dy * sinR;
75407
+ const localY = dx * sinR + dy * cosR;
75408
+ return Math.abs(localX) <= width / 2 + EPSILON24 && Math.abs(localY) <= height / 2 + EPSILON24;
75409
+ };
75410
+ var isPointInBrepPour = (p, pour) => {
75411
+ const outerRing = pour.brep_shape.outer_ring.vertices.map((v) => ({
75412
+ x: v.x,
75413
+ y: v.y
75414
+ }));
75415
+ if (!isPointInRing2(p, outerRing)) return false;
75416
+ for (const innerRing of pour.brep_shape.inner_rings) {
75417
+ const points = innerRing.vertices.map((v) => ({ x: v.x, y: v.y }));
75418
+ if (isPointInRing2(p, points)) return false;
75419
+ }
75420
+ return true;
75421
+ };
75422
+ var isPointInCopperPour = (point6, pour) => {
75423
+ if (pour.shape === "rect") {
75424
+ return isPointInRectPour(point6, pour);
75425
+ }
75426
+ if (pour.shape === "brep") {
75427
+ return isPointInBrepPour(point6, pour);
75428
+ }
75429
+ return false;
75430
+ };
75431
+ var isTraceConnectedToSourceNet = (trace, sourceNetId, sourceTraceById) => {
75432
+ if (trace.source_trace_id === sourceNetId) return true;
75433
+ if (!trace.source_trace_id) return false;
75434
+ const sourceTrace = sourceTraceById.get(trace.source_trace_id);
75435
+ if (!sourceTrace) return false;
75436
+ return sourceTrace.connected_source_net_ids.includes(sourceNetId);
75437
+ };
75438
+ var isSegmentFullyInsideCopperPour = (start, end, pour) => {
75439
+ const dx = end.x - start.x;
75440
+ const dy = end.y - start.y;
75441
+ const length8 = Math.hypot(dx, dy);
75442
+ if (length8 <= EPSILON24) return false;
75443
+ const samples = [0, 0.25, 0.5, 0.75, 1];
75444
+ return samples.every(
75445
+ (t) => isPointInCopperPour(
75446
+ {
75447
+ x: start.x + dx * t,
75448
+ y: start.y + dy * t
75449
+ },
75450
+ pour
75451
+ )
75452
+ );
75453
+ };
75454
+ var markTraceSegmentsInsideCopperPour = ({
75455
+ db,
75456
+ copperPour
75457
+ }) => {
75458
+ if (!copperPour.source_net_id) return;
75459
+ const sourceTraceById = new Map(
75460
+ db.source_trace.list().map((sourceTrace) => [sourceTrace.source_trace_id, sourceTrace])
75461
+ );
75462
+ for (const trace of db.pcb_trace.list()) {
75463
+ if (!isTraceConnectedToSourceNet(
75464
+ trace,
75465
+ copperPour.source_net_id,
75466
+ sourceTraceById
75467
+ )) {
75468
+ continue;
75469
+ }
75470
+ let routeChanged = false;
75471
+ const nextRoute = trace.route.map((routePoint) => ({ ...routePoint }));
75472
+ for (let i = 0; i < nextRoute.length - 1; i++) {
75473
+ const fromRoutePoint = nextRoute[i];
75474
+ const toRoutePoint = nextRoute[i + 1];
75475
+ if (!fromRoutePoint || !toRoutePoint) continue;
75476
+ if (!isWireRoutePoint(fromRoutePoint) || !isWireRoutePoint(toRoutePoint))
75477
+ continue;
75478
+ if (fromRoutePoint.layer !== copperPour.layer || toRoutePoint.layer !== copperPour.layer)
75479
+ continue;
75480
+ if (isSegmentFullyInsideCopperPour(
75481
+ { x: fromRoutePoint.x, y: fromRoutePoint.y },
75482
+ { x: toRoutePoint.x, y: toRoutePoint.y },
75483
+ copperPour
75484
+ )) {
75485
+ fromRoutePoint.is_inside_copper_pour = true;
75486
+ fromRoutePoint.copper_pour_id = copperPour.pcb_copper_pour_id;
75487
+ toRoutePoint.is_inside_copper_pour = true;
75488
+ toRoutePoint.copper_pour_id = copperPour.pcb_copper_pour_id;
75489
+ routeChanged = true;
75490
+ }
75491
+ }
75492
+ if (routeChanged) {
75493
+ db.pcb_trace.update(trace.pcb_trace_id, { route: nextRoute });
75494
+ }
75495
+ }
75496
+ };
75497
+
75498
+ // lib/components/primitive-components/CopperPour/CopperPour_doInitialPcbCopperPourRender.ts
75499
+ var pendingCopperPourRenders = /* @__PURE__ */ new WeakMap();
75500
+ var DEFAULT_THERMAL_RELIEF_SPOKE_WIDTH_MM = 0.3;
75501
+ var renderAllCopperPoursForSubcircuit = async (subcircuit) => {
75502
+ if (!subcircuit.root) return;
75503
+ const { db } = subcircuit.root;
75504
+ const copperPours = subcircuit.selectAll("copperpour").filter((copperPour) => copperPour.getSubcircuit() === subcircuit);
75505
+ const resolvedCopperPours = [];
75506
+ for (const copperPour of copperPours) {
75507
+ const { _parsedProps: props } = copperPour;
75508
+ const net = subcircuit.selectOne(props.connectsTo);
75509
+ const sourceNetId = net?.source_net_id;
75510
+ if (!sourceNetId) {
75511
+ copperPour.renderError(
75512
+ `Net "${props.connectsTo}" not found for copper pour`
75513
+ );
75514
+ continue;
75515
+ }
75516
+ resolvedCopperPours.push({ copperPour, sourceNetId });
75517
+ }
75518
+ if (resolvedCopperPours.length === 0) return;
75519
+ const circuitJson = db.toArray();
75520
+ const boardComponent = subcircuit._getBoard();
75521
+ const pcbBoard = boardComponent?.pcb_board_id ? db.pcb_board.get(boardComponent.pcb_board_id) : void 0;
75522
+ let resolvedPcbBoardOutline = pcbBoard?.outline?.length ? pcbBoard.outline : void 0;
75523
+ if (!resolvedPcbBoardOutline && pcbBoard?.width !== void 0 && pcbBoard.height !== void 0) {
75524
+ const { center, width, height } = pcbBoard;
75525
+ resolvedPcbBoardOutline = [
75526
+ { x: center.x - width / 2, y: center.y - height / 2 },
75527
+ { x: center.x + width / 2, y: center.y - height / 2 },
75528
+ { x: center.x + width / 2, y: center.y + height / 2 },
75529
+ { x: center.x - width / 2, y: center.y + height / 2 }
75530
+ ];
75531
+ }
75532
+ const inputProblem = convertCircuitJsonToInputProblem(
75533
+ circuitJson,
75534
+ resolvedCopperPours.map(({ copperPour, sourceNetId }) => {
75535
+ const { _parsedProps: props } = copperPour;
75536
+ const clearance = props.clearance ?? 0.2;
75537
+ return {
75538
+ layer: props.layer,
75539
+ subcircuit_id: subcircuit.subcircuit_id ?? void 0,
75540
+ source_net_id: sourceNetId,
75541
+ pad_margin: props.padMargin ?? clearance,
75542
+ trace_margin: props.traceMargin ?? clearance,
75543
+ pour_margin: clearance,
75544
+ board_edge_margin: props.boardEdgeMargin ?? clearance,
75545
+ board_edge_outline: copperPour._isImplicitCopperPour ? resolvedPcbBoardOutline : void 0,
75546
+ cutout_margin: props.cutoutMargin ?? clearance,
75547
+ ...props.useThermalReliefs ? {
75548
+ use_thermal_reliefs: true,
75549
+ thermal_relief_spoke_width: DEFAULT_THERMAL_RELIEF_SPOKE_WIDTH_MM
75550
+ } : {},
75551
+ outline: props.outline ?? resolvedPcbBoardOutline
75552
+ };
75553
+ })
75554
+ );
75555
+ await initializeManifoldGeometry();
75556
+ const solver = new CopperPourPipelineSolver2(inputProblem);
75557
+ subcircuit.root.emit("solver:started", {
75558
+ type: "solver:started",
75559
+ solverName: "CopperPourPipelineSolver",
75560
+ solverParams: inputProblem,
75561
+ solverConstructorArgs: [inputProblem],
75562
+ componentName: subcircuit.getString()
75563
+ });
75564
+ const { brep_shapes_by_region } = solver.getOutput();
75565
+ for (const [
75566
+ regionIndex,
75567
+ { copperPour, sourceNetId }
75568
+ ] of resolvedCopperPours.entries()) {
75569
+ const { _parsedProps: props } = copperPour;
75570
+ const coveredWithSolderMask = props.coveredWithSolderMask ?? false;
75571
+ for (const brepShape of brep_shapes_by_region[regionIndex] ?? []) {
75572
+ const insertedPour = db.pcb_copper_pour.insert({
75573
+ shape: "brep",
75574
+ layer: props.layer,
75575
+ brep_shape: brepShape,
75576
+ source_net_id: sourceNetId,
75577
+ subcircuit_id: subcircuit.subcircuit_id ?? void 0,
75578
+ covered_with_solder_mask: coveredWithSolderMask
75579
+ });
75580
+ markTraceSegmentsInsideCopperPour({
75581
+ db,
75582
+ copperPour: insertedPour
75583
+ });
75584
+ }
75585
+ }
75586
+ };
75587
+ function CopperPour_doInitialPcbCopperPourRender(copperPour) {
75588
+ if (copperPour.root?.pcbDisabled) return;
75589
+ copperPour._queueAsyncEffect("PcbCopperPourRender", async () => {
75590
+ const subcircuit = copperPour.getSubcircuit();
75591
+ const pendingRender = pendingCopperPourRenders.get(subcircuit);
75592
+ if (pendingRender) {
75593
+ await pendingRender;
75594
+ return;
75595
+ }
75596
+ const renderPromise = renderAllCopperPoursForSubcircuit(subcircuit);
75597
+ pendingCopperPourRenders.set(subcircuit, renderPromise);
75598
+ try {
75599
+ await renderPromise;
75600
+ } finally {
75601
+ pendingCopperPourRenders.delete(subcircuit);
75602
+ }
75603
+ });
75604
+ }
75605
+
75606
+ // lib/components/primitive-components/CopperPour/CopperPour_doInitialPcbViaStitchRender.ts
75607
+ import { pcb_via as pcb_via3 } from "circuit-json";
75608
+ var renderViaStitchingForCopperPours = (copperPour) => {
75609
+ const subcircuit = copperPour.getSubcircuit();
75610
+ if (!subcircuit.root) return;
75611
+ const copperPours = subcircuit.selectAll("copperpour").filter(
75612
+ (candidateCopperPour) => candidateCopperPour.getSubcircuit() === subcircuit
75613
+ );
75614
+ if (copperPours[0] !== copperPour) return;
75615
+ const sourceNetIds = copperPours.flatMap((candidateCopperPour) => {
75616
+ const net = subcircuit.selectOne(
75617
+ candidateCopperPour._parsedProps.connectsTo
75618
+ );
75619
+ return net?.source_net_id ? [net.source_net_id] : [];
75620
+ });
75621
+ if (sourceNetIds.length === 0) return;
75622
+ const { db } = subcircuit.root;
75623
+ const pcbStyle = copperPour.getInheritedMergedProperty("pcbStyle");
75624
+ const { holeDiameter, padDiameter } = getViaDiameterDefaults(pcbStyle);
75625
+ const boardComponent = copperPour._getBoard();
75626
+ const pcbBoard = boardComponent?.pcb_board_id ? db.pcb_board.get(boardComponent.pcb_board_id) : void 0;
75627
+ const solverInput = {
75628
+ circuitJson: db.toArray(),
75629
+ options: {
75630
+ sourceNetIds: [...new Set(sourceNetIds)],
75631
+ viaHoleDiameter: pcbBoard?.min_via_hole_diameter ?? holeDiameter,
75632
+ viaOuterDiameter: pcbBoard?.min_via_pad_diameter ?? padDiameter,
75633
+ viaStitchPitch: boardComponent?._parsedProps.viaStitchPitch
75634
+ }
75635
+ };
75636
+ const solver = new ViaStitchSolver(solverInput);
75637
+ subcircuit.root.emit("solver:started", {
75638
+ type: "solver:started",
75639
+ solverName: "ViaStitchSolver",
75640
+ solverParams: solverInput,
75641
+ solverConstructorArgs: [solverInput],
75642
+ componentName: subcircuit.getString()
75643
+ });
75644
+ solver.solve();
75645
+ if (solver.failed) {
75646
+ throw new Error(solver.error ?? "Via stitching solver failed");
75647
+ }
75648
+ for (const pcbVia of solver.getOutput().pcbVias) {
75649
+ const { pcb_via_id: _solverViaId, ...pcbViaInput } = pcb_via3.parse(pcbVia);
75650
+ const insertedVia = db.pcb_via.insert({
75651
+ ...pcbViaInput,
75652
+ tented_on_top: void 0,
75653
+ tented_on_bottom: void 0
75654
+ });
75655
+ boardComponent?._generatedStitchingViaIds?.add(insertedVia.pcb_via_id);
75656
+ }
75657
+ };
75658
+ function CopperPour_doInitialPcbViaStitchRender(copperPour) {
75659
+ if (copperPour.root?.pcbDisabled || !copperPour.root?._featurePcbViaStitching)
75660
+ return;
75661
+ if (!copperPour._getBoard()?._parsedProps.enableViaStitching) return;
75662
+ copperPour._queueAsyncEffect("PcbViaStitchRender", async () => {
75663
+ renderViaStitchingForCopperPours(copperPour);
75664
+ });
75665
+ }
75666
+
75667
+ // lib/components/primitive-components/CopperPour/CopperPour.ts
75668
+ var CopperPour = class extends PrimitiveComponent2 {
75669
+ isPcbPrimitive = true;
75670
+ _isImplicitCopperPour = false;
75671
+ get config() {
75672
+ return {
75673
+ componentName: "CopperPour",
75674
+ zodProps: copperPourProps
75675
+ };
75676
+ }
75677
+ getPcbSize() {
75678
+ return { width: 0, height: 0 };
75679
+ }
75680
+ doInitialCreateNetsFromProps() {
75681
+ const { _parsedProps: props } = this;
75682
+ createNetsFromProps(this, [props.connectsTo]);
75683
+ }
75684
+ doInitialPcbCopperPourRender() {
75685
+ CopperPour_doInitialPcbCopperPourRender(this);
75686
+ }
75687
+ doInitialPcbViaStitchRender() {
75688
+ CopperPour_doInitialPcbViaStitchRender(this);
75689
+ }
75690
+ };
75691
+
75728
75692
  // lib/components/primitive-components/AssemblyDevice.ts
75729
75693
  import { assemblyDeviceProps } from "@tscircuit/props";
75730
75694
  import { identity as identity10 } from "transformation-matrix";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tscircuit/core",
3
3
  "type": "module",
4
- "version": "0.0.1966",
4
+ "version": "0.0.1968",
5
5
  "types": "dist/index.d.ts",
6
6
  "main": "dist/index.js",
7
7
  "module": "dist/index.js",