@tscircuit/core 0.0.706 → 0.0.708

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
@@ -360,6 +360,7 @@ declare abstract class PrimitiveComponent<ZodProps extends ZodType = any> extend
360
360
  fallbackUnassignedName?: string;
361
361
  constructor(props: z.input<ZodProps>);
362
362
  setProps(props: Partial<z.input<ZodProps>>): void;
363
+ _getPcbRotationBeforeLayout(): number | null;
363
364
  /**
364
365
  * Computes a transformation matrix from the props of this component for PCB
365
366
  * components
@@ -13381,13 +13382,13 @@ declare const voltageSourceProps: z.ZodObject<{
13381
13382
  key?: any;
13382
13383
  footprint?: _tscircuit_props.FootprintProp | undefined;
13383
13384
  relative?: boolean | undefined;
13385
+ pcbRotation?: number | undefined;
13384
13386
  layer?: "top" | "bottom" | "inner1" | "inner2" | "inner3" | "inner4" | "inner5" | "inner6" | undefined;
13385
13387
  phase?: number | undefined;
13386
13388
  pcbX?: number | undefined;
13387
13389
  voltage?: number | undefined;
13388
13390
  frequency?: number | undefined;
13389
13391
  pcbY?: number | undefined;
13390
- pcbRotation?: number | undefined;
13391
13392
  pcbPositionAnchor?: string | undefined;
13392
13393
  schX?: number | undefined;
13393
13394
  schY?: number | undefined;
@@ -13536,6 +13537,7 @@ declare const voltageSourceProps: z.ZodObject<{
13536
13537
  key?: any;
13537
13538
  footprint?: _tscircuit_props.FootprintProp | undefined;
13538
13539
  relative?: boolean | undefined;
13540
+ pcbRotation?: string | number | undefined;
13539
13541
  layer?: "top" | "bottom" | "inner1" | "inner2" | "inner3" | "inner4" | "inner5" | "inner6" | {
13540
13542
  name: "top" | "bottom" | "inner1" | "inner2" | "inner3" | "inner4" | "inner5" | "inner6";
13541
13543
  } | undefined;
@@ -13544,7 +13546,6 @@ declare const voltageSourceProps: z.ZodObject<{
13544
13546
  voltage?: string | number | undefined;
13545
13547
  frequency?: string | number | undefined;
13546
13548
  pcbY?: string | number | undefined;
13547
- pcbRotation?: string | number | undefined;
13548
13549
  pcbPositionAnchor?: string | undefined;
13549
13550
  schX?: string | number | undefined;
13550
13551
  schY?: string | number | undefined;
@@ -14295,13 +14296,13 @@ declare class VoltageSource extends NormalComponent<typeof voltageSourceProps, "
14295
14296
  key?: any;
14296
14297
  footprint?: _tscircuit_props.FootprintProp | undefined;
14297
14298
  relative?: boolean | undefined;
14299
+ pcbRotation?: number | undefined;
14298
14300
  layer?: "top" | "bottom" | "inner1" | "inner2" | "inner3" | "inner4" | "inner5" | "inner6" | undefined;
14299
14301
  phase?: number | undefined;
14300
14302
  pcbX?: number | undefined;
14301
14303
  voltage?: number | undefined;
14302
14304
  frequency?: number | undefined;
14303
14305
  pcbY?: number | undefined;
14304
- pcbRotation?: number | undefined;
14305
14306
  pcbPositionAnchor?: string | undefined;
14306
14307
  schX?: number | undefined;
14307
14308
  schY?: number | undefined;
@@ -14450,6 +14451,7 @@ declare class VoltageSource extends NormalComponent<typeof voltageSourceProps, "
14450
14451
  key?: any;
14451
14452
  footprint?: _tscircuit_props.FootprintProp | undefined;
14452
14453
  relative?: boolean | undefined;
14454
+ pcbRotation?: string | number | undefined;
14453
14455
  layer?: "top" | "bottom" | "inner1" | "inner2" | "inner3" | "inner4" | "inner5" | "inner6" | {
14454
14456
  name: "top" | "bottom" | "inner1" | "inner2" | "inner3" | "inner4" | "inner5" | "inner6";
14455
14457
  } | undefined;
@@ -14458,7 +14460,6 @@ declare class VoltageSource extends NormalComponent<typeof voltageSourceProps, "
14458
14460
  voltage?: string | number | undefined;
14459
14461
  frequency?: string | number | undefined;
14460
14462
  pcbY?: string | number | undefined;
14461
- pcbRotation?: string | number | undefined;
14462
14463
  pcbPositionAnchor?: string | undefined;
14463
14464
  schX?: string | number | undefined;
14464
14465
  schY?: string | number | undefined;
@@ -15644,7 +15645,7 @@ declare class FabricationNotePath extends PrimitiveComponent<typeof fabricationN
15644
15645
  }>>;
15645
15646
  pcbRelative: zod.ZodOptional<zod.ZodBoolean>;
15646
15647
  relative: zod.ZodOptional<zod.ZodBoolean>;
15647
- }, "pcbX" | "pcbY" | "pcbRotation"> & {
15648
+ }, "pcbRotation" | "pcbX" | "pcbY"> & {
15648
15649
  route: zod.ZodArray<zod.ZodObject<{
15649
15650
  x: zod.ZodEffects<zod.ZodUnion<[zod.ZodString, zod.ZodNumber]>, number, string | number>;
15650
15651
  y: zod.ZodEffects<zod.ZodUnion<[zod.ZodString, zod.ZodNumber]>, number, string | number>;
@@ -15831,7 +15832,7 @@ declare class BreakoutPoint extends PrimitiveComponent<typeof breakoutPointProps
15831
15832
  }>>;
15832
15833
  pcbRelative: zod.ZodOptional<zod.ZodBoolean>;
15833
15834
  relative: zod.ZodOptional<zod.ZodBoolean>;
15834
- }, "layer" | "pcbRotation"> & {
15835
+ }, "pcbRotation" | "layer"> & {
15835
15836
  connection: zod.ZodString;
15836
15837
  }, "strip", zod.ZodTypeAny, {
15837
15838
  connection: string;
@@ -16129,7 +16130,7 @@ declare class PlatedHole extends PrimitiveComponent<typeof platedHoleProps> {
16129
16130
  }>>;
16130
16131
  pcbRelative: zod.ZodOptional<zod.ZodBoolean>;
16131
16132
  relative: zod.ZodOptional<zod.ZodBoolean>;
16132
- }, "layer" | "pcbRotation"> & {
16133
+ }, "pcbRotation" | "layer"> & {
16133
16134
  name: zod.ZodOptional<zod.ZodString>;
16134
16135
  connectsTo: zod.ZodOptional<zod.ZodUnion<[zod.ZodString, zod.ZodArray<zod.ZodString, "many">]>>;
16135
16136
  shape: zod.ZodLiteral<"circle">;
@@ -16176,7 +16177,7 @@ declare class PlatedHole extends PrimitiveComponent<typeof platedHoleProps> {
16176
16177
  }>>;
16177
16178
  pcbRelative: zod.ZodOptional<zod.ZodBoolean>;
16178
16179
  relative: zod.ZodOptional<zod.ZodBoolean>;
16179
- }, "layer" | "pcbRotation"> & {
16180
+ }, "pcbRotation" | "layer"> & {
16180
16181
  name: zod.ZodOptional<zod.ZodString>;
16181
16182
  connectsTo: zod.ZodOptional<zod.ZodUnion<[zod.ZodString, zod.ZodArray<zod.ZodString, "many">]>>;
16182
16183
  shape: zod.ZodLiteral<"oval">;
@@ -16299,7 +16300,7 @@ declare class PlatedHole extends PrimitiveComponent<typeof platedHoleProps> {
16299
16300
  }>>;
16300
16301
  pcbRelative: zod.ZodOptional<zod.ZodBoolean>;
16301
16302
  relative: zod.ZodOptional<zod.ZodBoolean>;
16302
- }, "layer" | "pcbRotation"> & {
16303
+ }, "pcbRotation" | "layer"> & {
16303
16304
  name: zod.ZodOptional<zod.ZodString>;
16304
16305
  connectsTo: zod.ZodOptional<zod.ZodUnion<[zod.ZodString, zod.ZodArray<zod.ZodString, "many">]>>;
16305
16306
  shape: zod.ZodLiteral<"circular_hole_with_rect_pad">;
@@ -16355,7 +16356,7 @@ declare class PlatedHole extends PrimitiveComponent<typeof platedHoleProps> {
16355
16356
  }>>;
16356
16357
  pcbRelative: zod.ZodOptional<zod.ZodBoolean>;
16357
16358
  relative: zod.ZodOptional<zod.ZodBoolean>;
16358
- }, "layer" | "pcbRotation"> & {
16359
+ }, "pcbRotation" | "layer"> & {
16359
16360
  name: zod.ZodOptional<zod.ZodString>;
16360
16361
  connectsTo: zod.ZodOptional<zod.ZodUnion<[zod.ZodString, zod.ZodArray<zod.ZodString, "many">]>>;
16361
16362
  shape: zod.ZodLiteral<"pill_hole_with_rect_pad">;
@@ -16662,7 +16663,7 @@ declare class SilkscreenPath extends PrimitiveComponent<typeof silkscreenPathPro
16662
16663
  }>>;
16663
16664
  pcbRelative: zod.ZodOptional<zod.ZodBoolean>;
16664
16665
  relative: zod.ZodOptional<zod.ZodBoolean>;
16665
- }, "pcbX" | "pcbY" | "pcbRotation"> & {
16666
+ }, "pcbRotation" | "pcbX" | "pcbY"> & {
16666
16667
  route: zod.ZodArray<zod.ZodObject<{
16667
16668
  x: zod.ZodEffects<zod.ZodUnion<[zod.ZodString, zod.ZodNumber]>, number, string | number>;
16668
16669
  y: zod.ZodEffects<zod.ZodUnion<[zod.ZodString, zod.ZodNumber]>, number, string | number>;
@@ -16892,7 +16893,7 @@ declare class SilkscreenLine extends PrimitiveComponent<typeof silkscreenLinePro
16892
16893
  }>>;
16893
16894
  pcbRelative: zod.ZodOptional<zod.ZodBoolean>;
16894
16895
  relative: zod.ZodOptional<zod.ZodBoolean>;
16895
- }, "pcbX" | "pcbY" | "pcbRotation"> & {
16896
+ }, "pcbRotation" | "pcbX" | "pcbY"> & {
16896
16897
  strokeWidth: zod.ZodEffects<zod.ZodUnion<[zod.ZodString, zod.ZodNumber]>, number, string | number>;
16897
16898
  x1: zod.ZodEffects<zod.ZodUnion<[zod.ZodString, zod.ZodNumber]>, number, string | number>;
16898
16899
  y1: zod.ZodEffects<zod.ZodUnion<[zod.ZodString, zod.ZodNumber]>, number, string | number>;
@@ -17772,7 +17773,7 @@ declare class Cutout extends PrimitiveComponent<typeof cutoutProps> {
17772
17773
  }>>;
17773
17774
  pcbRelative: zod.ZodOptional<zod.ZodBoolean>;
17774
17775
  relative: zod.ZodOptional<zod.ZodBoolean>;
17775
- }, "layer" | "pcbRotation"> & {
17776
+ }, "pcbRotation" | "layer"> & {
17776
17777
  name: zod.ZodOptional<zod.ZodString>;
17777
17778
  shape: zod.ZodLiteral<"rect">;
17778
17779
  width: zod.ZodEffects<zod.ZodUnion<[zod.ZodString, zod.ZodNumber]>, number, string | number>;
@@ -17813,7 +17814,7 @@ declare class Cutout extends PrimitiveComponent<typeof cutoutProps> {
17813
17814
  }>>;
17814
17815
  pcbRelative: zod.ZodOptional<zod.ZodBoolean>;
17815
17816
  relative: zod.ZodOptional<zod.ZodBoolean>;
17816
- }, "layer" | "pcbRotation"> & {
17817
+ }, "pcbRotation" | "layer"> & {
17817
17818
  name: zod.ZodOptional<zod.ZodString>;
17818
17819
  shape: zod.ZodLiteral<"circle">;
17819
17820
  radius: zod.ZodEffects<zod.ZodUnion<[zod.ZodString, zod.ZodNumber]>, number, string | number>;
@@ -17851,7 +17852,7 @@ declare class Cutout extends PrimitiveComponent<typeof cutoutProps> {
17851
17852
  }>>;
17852
17853
  pcbRelative: zod.ZodOptional<zod.ZodBoolean>;
17853
17854
  relative: zod.ZodOptional<zod.ZodBoolean>;
17854
- }, "layer" | "pcbRotation"> & {
17855
+ }, "pcbRotation" | "layer"> & {
17855
17856
  name: zod.ZodOptional<zod.ZodString>;
17856
17857
  shape: zod.ZodLiteral<"polygon">;
17857
17858
  points: zod.ZodArray<zod.ZodObject<{
@@ -18830,6 +18831,7 @@ declare class Battery extends NormalComponent<typeof batteryProps, PassivePorts>
18830
18831
  }
18831
18832
 
18832
18833
  declare class PinHeader extends NormalComponent<typeof pinHeaderProps> {
18834
+ _getPcbRotationBeforeLayout(): number | null;
18833
18835
  get config(): {
18834
18836
  componentName: string;
18835
18837
  zodProps: zod.ZodObject<{
@@ -19431,6 +19433,7 @@ declare class PinHeader extends NormalComponent<typeof pinHeaderProps> {
19431
19433
  pcbPinLabels: zod.ZodOptional<zod.ZodRecord<zod.ZodString, zod.ZodString>>;
19432
19434
  doubleRow: zod.ZodOptional<zod.ZodBoolean>;
19433
19435
  rightAngle: zod.ZodOptional<zod.ZodBoolean>;
19436
+ pcbOrientation: zod.ZodOptional<zod.ZodEnum<["vertical", "horizontal"]>>;
19434
19437
  holeDiameter: zod.ZodOptional<zod.ZodEffects<zod.ZodUnion<[zod.ZodString, zod.ZodNumber]>, number, string | number>>;
19435
19438
  platedDiameter: zod.ZodOptional<zod.ZodEffects<zod.ZodUnion<[zod.ZodString, zod.ZodNumber]>, number, string | number>>;
19436
19439
  pinLabels: zod.ZodOptional<zod.ZodUnion<[zod.ZodRecord<zod.ZodString, zod.ZodString>, zod.ZodArray<zod.ZodString, "many">]>>;
@@ -19766,6 +19769,7 @@ declare class PinHeader extends NormalComponent<typeof pinHeaderProps> {
19766
19769
  showSilkscreenPinLabels?: boolean | undefined;
19767
19770
  doubleRow?: boolean | undefined;
19768
19771
  rightAngle?: boolean | undefined;
19772
+ pcbOrientation?: "vertical" | "horizontal" | undefined;
19769
19773
  platedDiameter?: number | undefined;
19770
19774
  facingDirection?: "left" | "right" | undefined;
19771
19775
  }, {
@@ -19969,6 +19973,7 @@ declare class PinHeader extends NormalComponent<typeof pinHeaderProps> {
19969
19973
  showSilkscreenPinLabels?: boolean | undefined;
19970
19974
  doubleRow?: boolean | undefined;
19971
19975
  rightAngle?: boolean | undefined;
19976
+ pcbOrientation?: "vertical" | "horizontal" | undefined;
19972
19977
  platedDiameter?: string | number | undefined;
19973
19978
  facingDirection?: "left" | "right" | undefined;
19974
19979
  }>;
package/dist/index.js CHANGED
@@ -13,7 +13,7 @@ __export(components_exports, {
13
13
  BreakoutPoint: () => BreakoutPoint,
14
14
  Capacitor: () => Capacitor,
15
15
  Chip: () => Chip,
16
- Constraint: () => Constraint2,
16
+ Constraint: () => Constraint3,
17
17
  Crystal: () => Crystal,
18
18
  Cutout: () => Cutout,
19
19
  Diode: () => Diode,
@@ -685,15 +685,23 @@ var PrimitiveComponent2 = class extends Renderable {
685
685
  });
686
686
  this.parent?.onChildChanged?.(this);
687
687
  }
688
+ _getPcbRotationBeforeLayout() {
689
+ const { pcbRotation } = this.props;
690
+ if (typeof pcbRotation === "string") {
691
+ return parseFloat(pcbRotation);
692
+ }
693
+ return pcbRotation ?? null;
694
+ }
688
695
  /**
689
696
  * Computes a transformation matrix from the props of this component for PCB
690
697
  * components
691
698
  */
692
699
  computePcbPropsTransform() {
693
700
  const { _parsedProps: props } = this;
701
+ const rotation4 = this._getPcbRotationBeforeLayout() ?? 0;
694
702
  const matrix = compose(
695
703
  translate(props.pcbX ?? 0, props.pcbY ?? 0),
696
- rotate((props.pcbRotation ?? 0) * Math.PI / 180)
704
+ rotate(rotation4 * Math.PI / 180)
697
705
  );
698
706
  return matrix;
699
707
  }
@@ -705,14 +713,14 @@ var PrimitiveComponent2 = class extends Renderable {
705
713
  * components positions before layout is applied
706
714
  */
707
715
  _computePcbGlobalTransformBeforeLayout() {
708
- const { _parsedProps: props } = this;
709
716
  const manualPlacement = this.getSubcircuit()._getPcbManualPlacementForComponent(this);
710
717
  if (manualPlacement && this.props.pcbX === void 0 && this.props.pcbY === void 0) {
718
+ const rotation4 = this._getPcbRotationBeforeLayout() ?? 0;
711
719
  return compose(
712
720
  this.parent?._computePcbGlobalTransformBeforeLayout() ?? identity(),
713
721
  compose(
714
722
  translate(manualPlacement.x, manualPlacement.y),
715
- rotate((props.pcbRotation ?? 0) * Math.PI / 180)
723
+ rotate(rotation4 * Math.PI / 180)
716
724
  )
717
725
  );
718
726
  }
@@ -720,13 +728,7 @@ var PrimitiveComponent2 = class extends Renderable {
720
728
  const primitiveContainer = this.getPrimitiveContainer();
721
729
  if (primitiveContainer) {
722
730
  const isFlipped = primitiveContainer._parsedProps.layer === "bottom";
723
- const containerCenter = primitiveContainer._getGlobalPcbPositionBeforeLayout();
724
731
  if (isFlipped) {
725
- const flipOperation = compose(
726
- translate(containerCenter.x, containerCenter.y),
727
- flipY(),
728
- translate(-containerCenter.x, -containerCenter.y)
729
- );
730
732
  return compose(
731
733
  this.parent?._computePcbGlobalTransformBeforeLayout() ?? identity(),
732
734
  flipY(),
@@ -9738,8 +9740,7 @@ function getPresetAutoroutingConfig(autorouterConfig) {
9738
9740
  }
9739
9741
  }
9740
9742
 
9741
- // lib/components/primitive-components/Group/Group_doInitialPcbLayoutPack.ts
9742
- import "@tscircuit/circuit-json-util";
9743
+ // lib/components/primitive-components/Group/Group_doInitialPcbLayoutPack/Group_doInitialPcbLayoutPack.ts
9743
9744
  import {
9744
9745
  pack,
9745
9746
  convertCircuitJsonToPackOutput,
@@ -9747,64 +9748,263 @@ import {
9747
9748
  getGraphicsFromPackOutput
9748
9749
  } from "calculate-packing";
9749
9750
  import { length as length4 } from "circuit-json";
9750
- import {
9751
- transformPCBElements
9752
- } from "@tscircuit/circuit-json-util";
9753
- import { translate as translate5, rotate as rotate2, compose as compose4 } from "transformation-matrix";
9754
9751
  import Debug7 from "debug";
9755
- var DEFAULT_MIN_GAP = "1mm";
9756
- var debug6 = Debug7("Group_doInitialPcbLayoutPack");
9752
+
9753
+ // lib/components/primitive-components/Group/Group_doInitialPcbLayoutPack/applyComponentConstraintClusters.ts
9754
+ import * as kiwi2 from "@lume/kiwi";
9755
+ var applyComponentConstraintClusters = (group, packInput) => {
9756
+ const constraints = group.children.filter(
9757
+ (c) => c.componentName === "Constraint" && c._parsedProps.pcb
9758
+ );
9759
+ const clusterByRoot = /* @__PURE__ */ new Map();
9760
+ const parent = {};
9761
+ const find = (x) => {
9762
+ if (parent[x] !== x) parent[x] = find(parent[x]);
9763
+ return parent[x];
9764
+ };
9765
+ const union = (a, b) => {
9766
+ const ra = find(a);
9767
+ const rb = find(b);
9768
+ if (ra !== rb) parent[rb] = ra;
9769
+ };
9770
+ const makeSet = (x) => {
9771
+ if (!(x in parent)) parent[x] = x;
9772
+ };
9773
+ const getIdFromSelector = (sel2) => {
9774
+ const name = sel2.startsWith(".") ? sel2.slice(1) : sel2;
9775
+ const child = group.children.find((c) => c.name === name);
9776
+ return child?.pcb_component_id ?? void 0;
9777
+ };
9778
+ for (const constraint of constraints) {
9779
+ const props = constraint._parsedProps;
9780
+ if ("left" in props && "right" in props) {
9781
+ const a = getIdFromSelector(props.left);
9782
+ const b = getIdFromSelector(props.right);
9783
+ if (a && b) {
9784
+ makeSet(a);
9785
+ makeSet(b);
9786
+ union(a, b);
9787
+ }
9788
+ } else if ("top" in props && "bottom" in props) {
9789
+ const a = getIdFromSelector(props.top);
9790
+ const b = getIdFromSelector(props.bottom);
9791
+ if (a && b) {
9792
+ makeSet(a);
9793
+ makeSet(b);
9794
+ union(a, b);
9795
+ }
9796
+ } else if ("for" in props && Array.isArray(props.for)) {
9797
+ const ids = props.for.map((s) => getIdFromSelector(s)).filter((s) => !!s);
9798
+ for (const id of ids) makeSet(id);
9799
+ for (let i = 1; i < ids.length; i++) union(ids[0], ids[i]);
9800
+ }
9801
+ }
9802
+ for (const id of Object.keys(parent)) {
9803
+ const rootId = find(id);
9804
+ if (!clusterByRoot.has(rootId))
9805
+ clusterByRoot.set(rootId, { componentIds: [], constraints: [] });
9806
+ clusterByRoot.get(rootId).componentIds.push(id);
9807
+ }
9808
+ for (const constraint of constraints) {
9809
+ const props = constraint._parsedProps;
9810
+ let compId;
9811
+ if ("left" in props) compId = getIdFromSelector(props.left);
9812
+ else if ("top" in props) compId = getIdFromSelector(props.top);
9813
+ else if ("for" in props) compId = getIdFromSelector(props.for[0]);
9814
+ if (!compId) continue;
9815
+ const root = find(compId);
9816
+ clusterByRoot.get(root)?.constraints.push(constraint);
9817
+ }
9818
+ const clusterMap = {};
9819
+ const packCompById = Object.fromEntries(
9820
+ packInput.components.map((c) => [c.componentId, c])
9821
+ );
9822
+ for (const [rootId, info] of clusterByRoot.entries()) {
9823
+ if (info.componentIds.length <= 1) continue;
9824
+ const solver = new kiwi2.Solver();
9825
+ const kVars = {};
9826
+ const getVar = (id, axis) => {
9827
+ const key = `${id}_${axis}`;
9828
+ if (!kVars[key]) kVars[key] = new kiwi2.Variable(key);
9829
+ return kVars[key];
9830
+ };
9831
+ const anchor = info.componentIds[0];
9832
+ solver.addConstraint(
9833
+ new kiwi2.Constraint(
9834
+ getVar(anchor, "x"),
9835
+ kiwi2.Operator.Eq,
9836
+ 0,
9837
+ kiwi2.Strength.required
9838
+ )
9839
+ );
9840
+ solver.addConstraint(
9841
+ new kiwi2.Constraint(
9842
+ getVar(anchor, "y"),
9843
+ kiwi2.Operator.Eq,
9844
+ 0,
9845
+ kiwi2.Strength.required
9846
+ )
9847
+ );
9848
+ for (const constraint of info.constraints) {
9849
+ const props = constraint._parsedProps;
9850
+ if ("xDist" in props) {
9851
+ const left = getIdFromSelector(props.left);
9852
+ const right = getIdFromSelector(props.right);
9853
+ if (left && right) {
9854
+ solver.addConstraint(
9855
+ new kiwi2.Constraint(
9856
+ new kiwi2.Expression(getVar(right, "x"), [-1, getVar(left, "x")]),
9857
+ kiwi2.Operator.Eq,
9858
+ props.xDist,
9859
+ kiwi2.Strength.required
9860
+ )
9861
+ );
9862
+ }
9863
+ } else if ("yDist" in props) {
9864
+ const top = getIdFromSelector(props.top);
9865
+ const bottom = getIdFromSelector(props.bottom);
9866
+ if (top && bottom) {
9867
+ solver.addConstraint(
9868
+ new kiwi2.Constraint(
9869
+ new kiwi2.Expression(getVar(top, "y"), [-1, getVar(bottom, "y")]),
9870
+ kiwi2.Operator.Eq,
9871
+ props.yDist,
9872
+ kiwi2.Strength.required
9873
+ )
9874
+ );
9875
+ }
9876
+ } else if ("sameX" in props && Array.isArray(props.for)) {
9877
+ const ids = props.for.map((s) => getIdFromSelector(s)).filter((s) => !!s);
9878
+ if (ids.length > 1) {
9879
+ const base = getVar(ids[0], "x");
9880
+ for (let i = 1; i < ids.length; i++) {
9881
+ solver.addConstraint(
9882
+ new kiwi2.Constraint(
9883
+ new kiwi2.Expression(getVar(ids[i], "x"), [-1, base]),
9884
+ kiwi2.Operator.Eq,
9885
+ 0,
9886
+ kiwi2.Strength.required
9887
+ )
9888
+ );
9889
+ }
9890
+ }
9891
+ } else if ("sameY" in props && Array.isArray(props.for)) {
9892
+ const ids = props.for.map((s) => getIdFromSelector(s)).filter((s) => !!s);
9893
+ if (ids.length > 1) {
9894
+ const base = getVar(ids[0], "y");
9895
+ for (let i = 1; i < ids.length; i++) {
9896
+ solver.addConstraint(
9897
+ new kiwi2.Constraint(
9898
+ new kiwi2.Expression(getVar(ids[i], "y"), [-1, base]),
9899
+ kiwi2.Operator.Eq,
9900
+ 0,
9901
+ kiwi2.Strength.required
9902
+ )
9903
+ );
9904
+ }
9905
+ }
9906
+ }
9907
+ }
9908
+ solver.updateVariables();
9909
+ const positions = {};
9910
+ for (const id of info.componentIds) {
9911
+ positions[id] = {
9912
+ x: getVar(id, "x").value(),
9913
+ y: getVar(id, "y").value()
9914
+ };
9915
+ }
9916
+ let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
9917
+ for (const id of info.componentIds) {
9918
+ const comp = packCompById[id];
9919
+ const pos = positions[id];
9920
+ if (!comp) continue;
9921
+ for (const pad of comp.pads) {
9922
+ const ax = pos.x + pad.offset.x;
9923
+ const ay = pos.y + pad.offset.y;
9924
+ minX = Math.min(minX, ax - pad.size.x / 2);
9925
+ maxX = Math.max(maxX, ax + pad.size.x / 2);
9926
+ minY = Math.min(minY, ay - pad.size.y / 2);
9927
+ maxY = Math.max(maxY, ay + pad.size.y / 2);
9928
+ }
9929
+ }
9930
+ const clusterCenter = { x: (minX + maxX) / 2, y: (minY + maxY) / 2 };
9931
+ const mergedPads = [];
9932
+ const relCenters = {};
9933
+ for (const id of info.componentIds) {
9934
+ const comp = packCompById[id];
9935
+ const pos = positions[id];
9936
+ if (!comp) continue;
9937
+ relCenters[id] = {
9938
+ x: pos.x - clusterCenter.x,
9939
+ y: pos.y - clusterCenter.y
9940
+ };
9941
+ for (const pad of comp.pads) {
9942
+ mergedPads.push({
9943
+ padId: pad.padId,
9944
+ networkId: pad.networkId,
9945
+ type: pad.type,
9946
+ size: pad.size,
9947
+ offset: {
9948
+ x: pos.x + pad.offset.x - clusterCenter.x,
9949
+ y: pos.y + pad.offset.y - clusterCenter.y
9950
+ }
9951
+ });
9952
+ }
9953
+ }
9954
+ packInput.components = packInput.components.filter(
9955
+ (c) => !info.componentIds.includes(c.componentId)
9956
+ );
9957
+ packInput.components.push({
9958
+ componentId: info.componentIds[0],
9959
+ pads: mergedPads,
9960
+ availableRotationDegrees: [0]
9961
+ });
9962
+ info.relativeCenters = relCenters;
9963
+ clusterMap[info.componentIds[0]] = info;
9964
+ }
9965
+ return clusterMap;
9966
+ };
9967
+
9968
+ // lib/components/primitive-components/Group/Group_doInitialPcbLayoutPack/applyPackOutput.ts
9969
+ import { translate as translate5, rotate as rotate2, compose as compose4 } from "transformation-matrix";
9970
+ import { transformPCBElements } from "@tscircuit/circuit-json-util";
9757
9971
  var isDescendantGroup = (db, groupId, ancestorId) => {
9758
9972
  if (groupId === ancestorId) return true;
9759
9973
  const group = db.source_group.get(groupId);
9760
9974
  if (!group || !group.parent_source_group_id) return false;
9761
9975
  return isDescendantGroup(db, group.parent_source_group_id, ancestorId);
9762
9976
  };
9763
- var Group_doInitialPcbLayoutPack = (group) => {
9977
+ var applyPackOutput = (group, packOutput, clusterMap) => {
9764
9978
  const { db } = group.root;
9765
- const { _parsedProps: props } = group;
9766
- const {
9767
- packOrderStrategy,
9768
- packPlacementStrategy,
9769
- gap: gapProp,
9770
- pcbGap,
9771
- // @ts-expect-error remove when props introduces pcbPackGap
9772
- pcbPackGap
9773
- } = props;
9774
- const gap = pcbPackGap ?? pcbGap ?? gapProp;
9775
- const gapMm = length4.parse(gap ?? DEFAULT_MIN_GAP);
9776
- const packInput = {
9777
- ...convertPackOutputToPackInput(
9778
- convertCircuitJsonToPackOutput(db.toArray(), {
9779
- source_group_id: group.source_group_id,
9780
- shouldAddInnerObstacles: true
9781
- })
9782
- ),
9783
- // @ts-expect-error we're missing some pack order strategies
9784
- orderStrategy: packOrderStrategy ?? "largest_to_smallest",
9785
- placementStrategy: packPlacementStrategy ?? "minimum_sum_squared_distance_to_network",
9786
- minGap: gapMm
9787
- };
9788
- if (debug6.enabled) {
9789
- group.root?.emit("debug:logOutput", {
9790
- type: "debug:logOutput",
9791
- name: `packInput-circuitjson-${group.name}`,
9792
- content: JSON.stringify(db.toArray())
9793
- });
9794
- group.root?.emit("debug:logOutput", {
9795
- type: "debug:logOutput",
9796
- name: `packInput-${group.name}`,
9797
- content: packInput
9798
- });
9799
- }
9800
- const packOutput = pack(packInput);
9801
- if (debug6.enabled) {
9802
- const graphics = getGraphicsFromPackOutput(packOutput);
9803
- graphics.title = `packOutput-${group.name}`;
9804
- global.debugGraphics?.push(graphics);
9805
- }
9806
9979
  for (const packedComponent of packOutput.components) {
9807
9980
  const { center, componentId, ccwRotationOffset, ccwRotationDegrees } = packedComponent;
9981
+ const cluster = clusterMap[componentId];
9982
+ if (cluster) {
9983
+ const rotationDegrees2 = ccwRotationDegrees ?? ccwRotationOffset ?? 0;
9984
+ const angleRad = rotationDegrees2 * Math.PI / 180;
9985
+ for (const memberId of cluster.componentIds) {
9986
+ const rel = cluster.relativeCenters[memberId];
9987
+ if (!rel) continue;
9988
+ const rotatedRel = {
9989
+ x: rel.x * Math.cos(angleRad) - rel.y * Math.sin(angleRad),
9990
+ y: rel.x * Math.sin(angleRad) + rel.y * Math.cos(angleRad)
9991
+ };
9992
+ const member = db.pcb_component.get(memberId);
9993
+ if (!member) continue;
9994
+ const originalCenter2 = member.center;
9995
+ const transformMatrix2 = compose4(
9996
+ group._computePcbGlobalTransformBeforeLayout(),
9997
+ translate5(center.x + rotatedRel.x, center.y + rotatedRel.y),
9998
+ rotate2(angleRad),
9999
+ translate5(-originalCenter2.x, -originalCenter2.y)
10000
+ );
10001
+ const related = db.toArray().filter(
10002
+ (elm) => "pcb_component_id" in elm && elm.pcb_component_id === memberId
10003
+ );
10004
+ transformPCBElements(related, transformMatrix2);
10005
+ }
10006
+ continue;
10007
+ }
9808
10008
  const pcbComponent = db.pcb_component.get(componentId);
9809
10009
  if (pcbComponent) {
9810
10010
  const currentGroupId = group.source_group_id;
@@ -9860,20 +10060,16 @@ var Group_doInitialPcbLayoutPack = (group) => {
9860
10060
  }
9861
10061
  }
9862
10062
  if ("pcb_component_id" in elm && elm.pcb_component_id) {
9863
- const pcbComponent2 = db.pcb_component.get(elm.pcb_component_id);
9864
- if (pcbComponent2?.source_component_id) {
9865
- const sourceComponent = db.source_component.get(
9866
- pcbComponent2.source_component_id
10063
+ const pcbComp = db.pcb_component.get(elm.pcb_component_id);
10064
+ if (pcbComp?.source_component_id) {
10065
+ const sourceComp = db.source_component.get(
10066
+ pcbComp.source_component_id
9867
10067
  );
9868
- if (sourceComponent?.source_group_id) {
9869
- if (sourceComponent.source_group_id === componentId) {
10068
+ if (sourceComp?.source_group_id) {
10069
+ if (sourceComp.source_group_id === componentId) {
9870
10070
  return true;
9871
10071
  }
9872
- if (isDescendantGroup(
9873
- db,
9874
- sourceComponent.source_group_id,
9875
- componentId
9876
- )) {
10072
+ if (isDescendantGroup(db, sourceComp.source_group_id, componentId)) {
9877
10073
  return true;
9878
10074
  }
9879
10075
  }
@@ -9886,6 +10082,56 @@ var Group_doInitialPcbLayoutPack = (group) => {
9886
10082
  }
9887
10083
  };
9888
10084
 
10085
+ // lib/components/primitive-components/Group/Group_doInitialPcbLayoutPack/Group_doInitialPcbLayoutPack.ts
10086
+ var DEFAULT_MIN_GAP = "1mm";
10087
+ var debug6 = Debug7("Group_doInitialPcbLayoutPack");
10088
+ var Group_doInitialPcbLayoutPack = (group) => {
10089
+ const { db } = group.root;
10090
+ const { _parsedProps: props } = group;
10091
+ const {
10092
+ packOrderStrategy,
10093
+ packPlacementStrategy,
10094
+ gap: gapProp,
10095
+ pcbGap,
10096
+ // @ts-expect-error remove when props introduces pcbPackGap
10097
+ pcbPackGap
10098
+ } = props;
10099
+ const gap = pcbPackGap ?? pcbGap ?? gapProp;
10100
+ const gapMm = length4.parse(gap ?? DEFAULT_MIN_GAP);
10101
+ const packInput = {
10102
+ ...convertPackOutputToPackInput(
10103
+ convertCircuitJsonToPackOutput(db.toArray(), {
10104
+ source_group_id: group.source_group_id,
10105
+ shouldAddInnerObstacles: true
10106
+ })
10107
+ ),
10108
+ // @ts-expect-error we're missing some pack order strategies
10109
+ orderStrategy: packOrderStrategy ?? "largest_to_smallest",
10110
+ placementStrategy: packPlacementStrategy ?? "minimum_sum_squared_distance_to_network",
10111
+ minGap: gapMm
10112
+ };
10113
+ const clusterMap = applyComponentConstraintClusters(group, packInput);
10114
+ if (debug6.enabled) {
10115
+ group.root?.emit("debug:logOutput", {
10116
+ type: "debug:logOutput",
10117
+ name: `packInput-circuitjson-${group.name}`,
10118
+ content: JSON.stringify(db.toArray())
10119
+ });
10120
+ group.root?.emit("debug:logOutput", {
10121
+ type: "debug:logOutput",
10122
+ name: `packInput-${group.name}`,
10123
+ content: packInput
10124
+ });
10125
+ }
10126
+ const packOutput = pack(packInput);
10127
+ if (debug6.enabled) {
10128
+ const graphics = getGraphicsFromPackOutput(packOutput);
10129
+ graphics.title = `packOutput-${group.name}`;
10130
+ global.debugGraphics?.push(graphics);
10131
+ }
10132
+ applyPackOutput(group, packOutput, clusterMap);
10133
+ };
10134
+
9889
10135
  // lib/components/primitive-components/Group/Group_doInitialPcbLayoutFlex.ts
9890
10136
  import { getMinimumFlexContainer as getMinimumFlexContainer2 } from "@tscircuit/circuit-json-util";
9891
10137
  import { RootFlexBox as RootFlexBox2 } from "@tscircuit/miniflex";
@@ -12694,7 +12940,7 @@ var edgeSpecifiers = [
12694
12940
  "bottomedge",
12695
12941
  "center"
12696
12942
  ];
12697
- var Constraint2 = class extends PrimitiveComponent2 {
12943
+ var Constraint3 = class extends PrimitiveComponent2 {
12698
12944
  get config() {
12699
12945
  return {
12700
12946
  componentName: "Constraint",
@@ -13434,6 +13680,11 @@ var Battery = class extends NormalComponent2 {
13434
13680
  // lib/components/normal-components/PinHeader.ts
13435
13681
  import { pinHeaderProps } from "@tscircuit/props";
13436
13682
  var PinHeader = class extends NormalComponent2 {
13683
+ _getPcbRotationBeforeLayout() {
13684
+ const orientationRotation = this.props.pcbOrientation === "vertical" ? -90 : 0;
13685
+ const baseRotation = super._getPcbRotationBeforeLayout() ?? 0;
13686
+ return baseRotation + orientationRotation;
13687
+ }
13437
13688
  get config() {
13438
13689
  return {
13439
13690
  componentName: "PinHeader",
@@ -14372,7 +14623,7 @@ import { identity as identity6 } from "transformation-matrix";
14372
14623
  var package_default = {
14373
14624
  name: "@tscircuit/core",
14374
14625
  type: "module",
14375
- version: "0.0.705",
14626
+ version: "0.0.707",
14376
14627
  types: "dist/index.d.ts",
14377
14628
  main: "dist/index.js",
14378
14629
  module: "dist/index.js",
@@ -14411,7 +14662,7 @@ var package_default = {
14411
14662
  "@tscircuit/matchpack": "^0.0.16",
14412
14663
  "@tscircuit/math-utils": "^0.0.21",
14413
14664
  "@tscircuit/miniflex": "^0.0.4",
14414
- "@tscircuit/props": "0.0.305",
14665
+ "@tscircuit/props": "0.0.307",
14415
14666
  "@tscircuit/schematic-autolayout": "^0.0.6",
14416
14667
  "@tscircuit/schematic-match-adapt": "^0.0.16",
14417
14668
  "@tscircuit/schematic-trace-solver": "^0.0.35",
@@ -14882,7 +15133,7 @@ export {
14882
15133
  Capacitor,
14883
15134
  Chip,
14884
15135
  Circuit,
14885
- Constraint2 as Constraint,
15136
+ Constraint3 as Constraint,
14886
15137
  Crystal,
14887
15138
  Cutout,
14888
15139
  Diode,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tscircuit/core",
3
3
  "type": "module",
4
- "version": "0.0.706",
4
+ "version": "0.0.708",
5
5
  "types": "dist/index.d.ts",
6
6
  "main": "dist/index.js",
7
7
  "module": "dist/index.js",
@@ -40,7 +40,7 @@
40
40
  "@tscircuit/matchpack": "^0.0.16",
41
41
  "@tscircuit/math-utils": "^0.0.21",
42
42
  "@tscircuit/miniflex": "^0.0.4",
43
- "@tscircuit/props": "0.0.305",
43
+ "@tscircuit/props": "0.0.307",
44
44
  "@tscircuit/schematic-autolayout": "^0.0.6",
45
45
  "@tscircuit/schematic-match-adapt": "^0.0.16",
46
46
  "@tscircuit/schematic-trace-solver": "^0.0.35",