@tscircuit/core 0.0.31 → 0.0.33
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 +106 -2
- package/dist/index.js +162 -54
- package/lib/components/index.ts +1 -0
- package/lib/components/primitive-components/Footprint.ts +99 -62
- package/lib/components/primitive-components/Hole.ts +65 -0
- package/lib/components/primitive-components/PlatedHole.ts +37 -9
- package/lib/soup/underscorifyPinStyles.ts +9 -7
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { ReactElement } from 'react';
|
|
|
6
6
|
import { Matrix } from 'transformation-matrix';
|
|
7
7
|
import { SchSymbol, BaseSymbolName } from 'schematic-symbols';
|
|
8
8
|
import * as Props from '@tscircuit/props';
|
|
9
|
-
import { traceProps, groupProps, boardProps, footprintProps, smtPadProps, resistorProps, ledProps, capacitorProps, traceHintProps, chipProps, jumperProps, silkscreenPathProps, platedHoleProps, constraintProps } from '@tscircuit/props';
|
|
9
|
+
import { traceProps, groupProps, boardProps, footprintProps, smtPadProps, resistorProps, ledProps, capacitorProps, traceHintProps, chipProps, jumperProps, silkscreenPathProps, platedHoleProps, constraintProps, holeProps } from '@tscircuit/props';
|
|
10
10
|
|
|
11
11
|
declare class Circuit {
|
|
12
12
|
firstChild: PrimitiveComponent | null;
|
|
@@ -3348,6 +3348,7 @@ declare class PlatedHole extends PrimitiveComponent<typeof platedHoleProps> {
|
|
|
3348
3348
|
name: "top" | "bottom" | "inner1" | "inner2" | "inner3" | "inner4" | "inner5" | "inner6";
|
|
3349
3349
|
}>>;
|
|
3350
3350
|
}, "pcbRotation" | "layer">, {
|
|
3351
|
+
name: zod.ZodOptional<zod.ZodString>;
|
|
3351
3352
|
shape: zod.ZodLiteral<"circle">;
|
|
3352
3353
|
holeDiameter: zod.ZodEffects<zod.ZodUnion<[zod.ZodString, zod.ZodNumber]>, number, string | number>;
|
|
3353
3354
|
outerDiameter: zod.ZodEffects<zod.ZodUnion<[zod.ZodString, zod.ZodNumber]>, number, string | number>;
|
|
@@ -3358,6 +3359,7 @@ declare class PlatedHole extends PrimitiveComponent<typeof platedHoleProps> {
|
|
|
3358
3359
|
outerDiameter: number;
|
|
3359
3360
|
pcbX?: number | undefined;
|
|
3360
3361
|
pcbY?: number | undefined;
|
|
3362
|
+
name?: string | undefined;
|
|
3361
3363
|
portHints?: (string | number)[] | undefined;
|
|
3362
3364
|
}, {
|
|
3363
3365
|
shape: "circle";
|
|
@@ -3365,6 +3367,7 @@ declare class PlatedHole extends PrimitiveComponent<typeof platedHoleProps> {
|
|
|
3365
3367
|
outerDiameter: string | number;
|
|
3366
3368
|
pcbX?: string | number | undefined;
|
|
3367
3369
|
pcbY?: string | number | undefined;
|
|
3370
|
+
name?: string | undefined;
|
|
3368
3371
|
portHints?: (string | number)[] | undefined;
|
|
3369
3372
|
}>, zod.ZodObject<zod.objectUtil.extendShape<Omit<{
|
|
3370
3373
|
pcbX: zod.ZodOptional<zod.ZodEffects<zod.ZodUnion<[zod.ZodString, zod.ZodNumber]>, number, string | number>>;
|
|
@@ -3380,6 +3383,7 @@ declare class PlatedHole extends PrimitiveComponent<typeof platedHoleProps> {
|
|
|
3380
3383
|
name: "top" | "bottom" | "inner1" | "inner2" | "inner3" | "inner4" | "inner5" | "inner6";
|
|
3381
3384
|
}>>;
|
|
3382
3385
|
}, "pcbRotation" | "layer">, {
|
|
3386
|
+
name: zod.ZodOptional<zod.ZodString>;
|
|
3383
3387
|
shape: zod.ZodLiteral<"oval">;
|
|
3384
3388
|
outerWidth: zod.ZodEffects<zod.ZodUnion<[zod.ZodString, zod.ZodNumber]>, number, string | number>;
|
|
3385
3389
|
outerHeight: zod.ZodEffects<zod.ZodUnion<[zod.ZodString, zod.ZodNumber]>, number, string | number>;
|
|
@@ -3394,6 +3398,7 @@ declare class PlatedHole extends PrimitiveComponent<typeof platedHoleProps> {
|
|
|
3394
3398
|
innerHeight: number;
|
|
3395
3399
|
pcbX?: number | undefined;
|
|
3396
3400
|
pcbY?: number | undefined;
|
|
3401
|
+
name?: string | undefined;
|
|
3397
3402
|
portHints?: (string | number)[] | undefined;
|
|
3398
3403
|
}, {
|
|
3399
3404
|
shape: "oval";
|
|
@@ -3403,6 +3408,7 @@ declare class PlatedHole extends PrimitiveComponent<typeof platedHoleProps> {
|
|
|
3403
3408
|
innerHeight: string | number;
|
|
3404
3409
|
pcbX?: string | number | undefined;
|
|
3405
3410
|
pcbY?: string | number | undefined;
|
|
3411
|
+
name?: string | undefined;
|
|
3406
3412
|
portHints?: (string | number)[] | undefined;
|
|
3407
3413
|
}>]>;
|
|
3408
3414
|
};
|
|
@@ -3410,6 +3416,24 @@ declare class PlatedHole extends PrimitiveComponent<typeof platedHoleProps> {
|
|
|
3410
3416
|
width: number;
|
|
3411
3417
|
height: number;
|
|
3412
3418
|
};
|
|
3419
|
+
_getCircuitJsonBounds(): {
|
|
3420
|
+
center: {
|
|
3421
|
+
x: number;
|
|
3422
|
+
y: number;
|
|
3423
|
+
};
|
|
3424
|
+
bounds: {
|
|
3425
|
+
left: number;
|
|
3426
|
+
top: number;
|
|
3427
|
+
right: number;
|
|
3428
|
+
bottom: number;
|
|
3429
|
+
};
|
|
3430
|
+
width: number;
|
|
3431
|
+
height: number;
|
|
3432
|
+
};
|
|
3433
|
+
_setPositionFromLayout(newCenter: {
|
|
3434
|
+
x: number;
|
|
3435
|
+
y: number;
|
|
3436
|
+
}): void;
|
|
3413
3437
|
doInitialPortMatching(): void;
|
|
3414
3438
|
doInitialPcbPrimitiveRender(): void;
|
|
3415
3439
|
}
|
|
@@ -3499,6 +3523,86 @@ declare class Constraint extends PrimitiveComponent<typeof constraintProps> {
|
|
|
3499
3523
|
};
|
|
3500
3524
|
}
|
|
3501
3525
|
|
|
3526
|
+
declare class Hole extends PrimitiveComponent<typeof holeProps> {
|
|
3527
|
+
pcb_hole_id: string | null;
|
|
3528
|
+
isPcbPrimitive: boolean;
|
|
3529
|
+
get config(): {
|
|
3530
|
+
zodProps: zod.ZodEffects<zod.ZodObject<zod.objectUtil.extendShape<Omit<{
|
|
3531
|
+
pcbX: zod.ZodOptional<zod.ZodEffects<zod.ZodUnion<[zod.ZodString, zod.ZodNumber]>, number, string | number>>;
|
|
3532
|
+
pcbY: zod.ZodOptional<zod.ZodEffects<zod.ZodUnion<[zod.ZodString, zod.ZodNumber]>, number, string | number>>;
|
|
3533
|
+
pcbRotation: zod.ZodOptional<zod.ZodEffects<zod.ZodUnion<[zod.ZodString, zod.ZodNumber]>, number, string | number>>;
|
|
3534
|
+
layer: zod.ZodOptional<zod.ZodEffects<zod.ZodUnion<[zod.ZodEnum<["top", "bottom", "inner1", "inner2", "inner3", "inner4", "inner5", "inner6"]>, zod.ZodObject<{
|
|
3535
|
+
name: zod.ZodEnum<["top", "bottom", "inner1", "inner2", "inner3", "inner4", "inner5", "inner6"]>;
|
|
3536
|
+
}, "strip", zod.ZodTypeAny, {
|
|
3537
|
+
name: "top" | "bottom" | "inner1" | "inner2" | "inner3" | "inner4" | "inner5" | "inner6";
|
|
3538
|
+
}, {
|
|
3539
|
+
name: "top" | "bottom" | "inner1" | "inner2" | "inner3" | "inner4" | "inner5" | "inner6";
|
|
3540
|
+
}>]>, "top" | "bottom" | "inner1" | "inner2" | "inner3" | "inner4" | "inner5" | "inner6", "top" | "bottom" | "inner1" | "inner2" | "inner3" | "inner4" | "inner5" | "inner6" | {
|
|
3541
|
+
name: "top" | "bottom" | "inner1" | "inner2" | "inner3" | "inner4" | "inner5" | "inner6";
|
|
3542
|
+
}>>;
|
|
3543
|
+
}, "pcbRotation">, {
|
|
3544
|
+
name: zod.ZodOptional<zod.ZodString>;
|
|
3545
|
+
diameter: zod.ZodOptional<zod.ZodEffects<zod.ZodUnion<[zod.ZodString, zod.ZodNumber]>, number, string | number>>;
|
|
3546
|
+
radius: zod.ZodOptional<zod.ZodEffects<zod.ZodUnion<[zod.ZodString, zod.ZodNumber]>, number, string | number>>;
|
|
3547
|
+
}>, "strip", zod.ZodTypeAny, {
|
|
3548
|
+
pcbX?: number | undefined;
|
|
3549
|
+
pcbY?: number | undefined;
|
|
3550
|
+
layer?: "top" | "bottom" | "inner1" | "inner2" | "inner3" | "inner4" | "inner5" | "inner6" | undefined;
|
|
3551
|
+
name?: string | undefined;
|
|
3552
|
+
radius?: number | undefined;
|
|
3553
|
+
diameter?: number | undefined;
|
|
3554
|
+
}, {
|
|
3555
|
+
pcbX?: string | number | undefined;
|
|
3556
|
+
pcbY?: string | number | undefined;
|
|
3557
|
+
layer?: "top" | "bottom" | "inner1" | "inner2" | "inner3" | "inner4" | "inner5" | "inner6" | {
|
|
3558
|
+
name: "top" | "bottom" | "inner1" | "inner2" | "inner3" | "inner4" | "inner5" | "inner6";
|
|
3559
|
+
} | undefined;
|
|
3560
|
+
name?: string | undefined;
|
|
3561
|
+
radius?: string | number | undefined;
|
|
3562
|
+
diameter?: string | number | undefined;
|
|
3563
|
+
}>, {
|
|
3564
|
+
diameter: number;
|
|
3565
|
+
radius: number;
|
|
3566
|
+
pcbX?: number | undefined;
|
|
3567
|
+
pcbY?: number | undefined;
|
|
3568
|
+
layer?: "top" | "bottom" | "inner1" | "inner2" | "inner3" | "inner4" | "inner5" | "inner6" | undefined;
|
|
3569
|
+
name?: string | undefined;
|
|
3570
|
+
}, {
|
|
3571
|
+
pcbX?: string | number | undefined;
|
|
3572
|
+
pcbY?: string | number | undefined;
|
|
3573
|
+
layer?: "top" | "bottom" | "inner1" | "inner2" | "inner3" | "inner4" | "inner5" | "inner6" | {
|
|
3574
|
+
name: "top" | "bottom" | "inner1" | "inner2" | "inner3" | "inner4" | "inner5" | "inner6";
|
|
3575
|
+
} | undefined;
|
|
3576
|
+
name?: string | undefined;
|
|
3577
|
+
radius?: string | number | undefined;
|
|
3578
|
+
diameter?: string | number | undefined;
|
|
3579
|
+
}>;
|
|
3580
|
+
};
|
|
3581
|
+
getPcbSize(): {
|
|
3582
|
+
width: number;
|
|
3583
|
+
height: number;
|
|
3584
|
+
};
|
|
3585
|
+
doInitialPcbPrimitiveRender(): void;
|
|
3586
|
+
_getCircuitJsonBounds(): {
|
|
3587
|
+
center: {
|
|
3588
|
+
x: number;
|
|
3589
|
+
y: number;
|
|
3590
|
+
};
|
|
3591
|
+
bounds: {
|
|
3592
|
+
left: number;
|
|
3593
|
+
top: number;
|
|
3594
|
+
right: number;
|
|
3595
|
+
bottom: number;
|
|
3596
|
+
};
|
|
3597
|
+
width: number;
|
|
3598
|
+
height: number;
|
|
3599
|
+
};
|
|
3600
|
+
_setPositionFromLayout(newCenter: {
|
|
3601
|
+
x: number;
|
|
3602
|
+
y: number;
|
|
3603
|
+
}): void;
|
|
3604
|
+
}
|
|
3605
|
+
|
|
3502
3606
|
declare global {
|
|
3503
3607
|
namespace JSX {
|
|
3504
3608
|
interface IntrinsicElements {
|
|
@@ -3544,4 +3648,4 @@ declare global {
|
|
|
3544
3648
|
}
|
|
3545
3649
|
}
|
|
3546
3650
|
|
|
3547
|
-
export { Board, Capacitor, Chip, Circuit, Constraint, Footprint, Group, type IRenderable, Jumper, Led, Net, NormalComponent, PlatedHole, Port, PrimitiveComponent, Project, Renderable, Resistor, SilkscreenPath, SmtPad, Trace, TraceHint };
|
|
3651
|
+
export { Board, Capacitor, Chip, Circuit, Constraint, Footprint, Group, Hole, type IRenderable, Jumper, Led, Net, NormalComponent, PlatedHole, Port, PrimitiveComponent, Project, Renderable, Resistor, SilkscreenPath, SmtPad, Trace, TraceHint };
|
package/dist/index.js
CHANGED
|
@@ -13,6 +13,7 @@ __export(components_exports, {
|
|
|
13
13
|
Constraint: () => Constraint2,
|
|
14
14
|
Footprint: () => Footprint,
|
|
15
15
|
Group: () => Group,
|
|
16
|
+
Hole: () => Hole,
|
|
16
17
|
Jumper: () => Jumper,
|
|
17
18
|
Led: () => Led,
|
|
18
19
|
Net: () => Net,
|
|
@@ -534,16 +535,15 @@ var Footprint = class extends PrimitiveComponent {
|
|
|
534
535
|
function getKVar(name) {
|
|
535
536
|
if (!(name in kVars)) {
|
|
536
537
|
kVars[name] = new kiwi.Variable(name);
|
|
538
|
+
solver.addEditVariable(kVars[name], kiwi.Strength.weak);
|
|
537
539
|
}
|
|
538
540
|
return kVars[name];
|
|
539
541
|
}
|
|
540
|
-
for (const { selector, bounds } of involvedComponents) {
|
|
542
|
+
for (const { selector, bounds: bounds2 } of involvedComponents) {
|
|
541
543
|
const kvx = getKVar(`${selector}_x`);
|
|
542
544
|
const kvy = getKVar(`${selector}_y`);
|
|
543
|
-
solver.
|
|
544
|
-
solver.
|
|
545
|
-
solver.suggestValue(kvx, bounds.center.x);
|
|
546
|
-
solver.suggestValue(kvy, bounds.center.y);
|
|
545
|
+
solver.suggestValue(kvx, bounds2.center.x);
|
|
546
|
+
solver.suggestValue(kvy, bounds2.center.y);
|
|
547
547
|
}
|
|
548
548
|
for (const constraint of constraints) {
|
|
549
549
|
const props = constraint._parsedProps;
|
|
@@ -566,7 +566,7 @@ var Footprint = class extends PrimitiveComponent {
|
|
|
566
566
|
} else if (edgeToEdge) {
|
|
567
567
|
const expr = new kiwi.Expression(
|
|
568
568
|
rightVar,
|
|
569
|
-
rightBounds.width / 2,
|
|
569
|
+
-rightBounds.width / 2,
|
|
570
570
|
[-1, leftVar],
|
|
571
571
|
-leftBounds.width / 2
|
|
572
572
|
);
|
|
@@ -579,50 +579,82 @@ var Footprint = class extends PrimitiveComponent {
|
|
|
579
579
|
)
|
|
580
580
|
);
|
|
581
581
|
}
|
|
582
|
+
} else if ("ydist" in props) {
|
|
583
|
+
const { ydist, top, bottom, edgeToEdge, centerToCenter } = props;
|
|
584
|
+
const topVar = getKVar(`${top}_y`);
|
|
585
|
+
const bottomVar = getKVar(`${bottom}_y`);
|
|
586
|
+
const topBounds = getComponentDetails(top)?.bounds;
|
|
587
|
+
const bottomBounds = getComponentDetails(bottom)?.bounds;
|
|
588
|
+
if (centerToCenter) {
|
|
589
|
+
const expr = new kiwi.Expression(topVar, [-1, bottomVar]);
|
|
590
|
+
solver.addConstraint(
|
|
591
|
+
new kiwi.Constraint(
|
|
592
|
+
expr,
|
|
593
|
+
kiwi.Operator.Eq,
|
|
594
|
+
props.ydist,
|
|
595
|
+
kiwi.Strength.required
|
|
596
|
+
)
|
|
597
|
+
);
|
|
598
|
+
} else if (edgeToEdge) {
|
|
599
|
+
const expr = new kiwi.Expression(
|
|
600
|
+
topVar,
|
|
601
|
+
topBounds.height / 2,
|
|
602
|
+
[-1, bottomVar],
|
|
603
|
+
-bottomBounds.height / 2
|
|
604
|
+
);
|
|
605
|
+
solver.addConstraint(
|
|
606
|
+
new kiwi.Constraint(
|
|
607
|
+
expr,
|
|
608
|
+
kiwi.Operator.Eq,
|
|
609
|
+
props.ydist,
|
|
610
|
+
kiwi.Strength.required
|
|
611
|
+
)
|
|
612
|
+
);
|
|
613
|
+
}
|
|
582
614
|
}
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
)
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
}
|
|
615
|
+
}
|
|
616
|
+
solver.updateVariables();
|
|
617
|
+
if (debug.enabled) {
|
|
618
|
+
console.log("Solution to layout constraints:");
|
|
619
|
+
console.table(
|
|
620
|
+
Object.entries(kVars).map(([key, kvar]) => ({
|
|
621
|
+
var: key,
|
|
622
|
+
val: kvar.value()
|
|
623
|
+
}))
|
|
624
|
+
);
|
|
625
|
+
}
|
|
626
|
+
const bounds = {
|
|
627
|
+
left: Infinity,
|
|
628
|
+
right: -Infinity,
|
|
629
|
+
top: -Infinity,
|
|
630
|
+
bottom: Infinity
|
|
631
|
+
};
|
|
632
|
+
for (const {
|
|
633
|
+
selector,
|
|
634
|
+
bounds: { width, height }
|
|
635
|
+
} of involvedComponents) {
|
|
636
|
+
const kvx = getKVar(`${selector}_x`);
|
|
637
|
+
const kvy = getKVar(`${selector}_y`);
|
|
638
|
+
const newLeft = kvx.value() - width / 2;
|
|
639
|
+
const newRight = kvx.value() + width / 2;
|
|
640
|
+
const newTop = kvy.value() + height / 2;
|
|
641
|
+
const newBottom = kvy.value() - height / 2;
|
|
642
|
+
bounds.left = Math.min(bounds.left, newLeft);
|
|
643
|
+
bounds.right = Math.max(bounds.right, newRight);
|
|
644
|
+
bounds.top = Math.max(bounds.top, newTop);
|
|
645
|
+
bounds.bottom = Math.min(bounds.bottom, newBottom);
|
|
646
|
+
}
|
|
647
|
+
const globalOffset = {
|
|
648
|
+
x: -(bounds.right + bounds.left) / 2,
|
|
649
|
+
y: -(bounds.top + bounds.bottom) / 2
|
|
650
|
+
};
|
|
651
|
+
for (const { component, selector } of involvedComponents) {
|
|
652
|
+
const kvx = getKVar(`${selector}_x`);
|
|
653
|
+
const kvy = getKVar(`${selector}_y`);
|
|
654
|
+
component._setPositionFromLayout({
|
|
655
|
+
x: kvx.value() + globalOffset.x,
|
|
656
|
+
y: kvy.value() + globalOffset.y
|
|
657
|
+
});
|
|
626
658
|
}
|
|
627
659
|
}
|
|
628
660
|
};
|
|
@@ -1163,6 +1195,29 @@ var PlatedHole = class extends PrimitiveComponent {
|
|
|
1163
1195
|
`getPcbSize for shape "${props.shape}" not implemented for ${this.componentName}`
|
|
1164
1196
|
);
|
|
1165
1197
|
}
|
|
1198
|
+
_getCircuitJsonBounds() {
|
|
1199
|
+
const { db } = this.root;
|
|
1200
|
+
const platedHole = db.pcb_plated_hole.get(this.pcb_plated_hole_id);
|
|
1201
|
+
const size = this.getPcbSize();
|
|
1202
|
+
return {
|
|
1203
|
+
center: { x: platedHole.x, y: platedHole.y },
|
|
1204
|
+
bounds: {
|
|
1205
|
+
left: platedHole.x - size.width / 2,
|
|
1206
|
+
top: platedHole.y - size.height / 2,
|
|
1207
|
+
right: platedHole.x + size.width / 2,
|
|
1208
|
+
bottom: platedHole.y + size.height / 2
|
|
1209
|
+
},
|
|
1210
|
+
width: size.width,
|
|
1211
|
+
height: size.height
|
|
1212
|
+
};
|
|
1213
|
+
}
|
|
1214
|
+
_setPositionFromLayout(newCenter) {
|
|
1215
|
+
const { db } = this.root;
|
|
1216
|
+
db.pcb_plated_hole.update(this.pcb_plated_hole_id, {
|
|
1217
|
+
x: newCenter.x,
|
|
1218
|
+
y: newCenter.y
|
|
1219
|
+
});
|
|
1220
|
+
}
|
|
1166
1221
|
doInitialPortMatching() {
|
|
1167
1222
|
const parentPorts = (this.parent?.children ?? []).filter(
|
|
1168
1223
|
(c) => c.componentName === "Port"
|
|
@@ -1184,19 +1239,19 @@ var PlatedHole = class extends PrimitiveComponent {
|
|
|
1184
1239
|
if (!props.portHints) return;
|
|
1185
1240
|
const position = this._getGlobalPcbPositionBeforeLayout();
|
|
1186
1241
|
if (props.shape === "circle") {
|
|
1187
|
-
const
|
|
1242
|
+
const pcb_plated_hole = db.pcb_plated_hole.insert({
|
|
1188
1243
|
pcb_component_id: this.parent?.pcb_component_id,
|
|
1189
1244
|
pcb_port_id: this.matchedPort?.pcb_port_id,
|
|
1190
|
-
|
|
1245
|
+
// @ts-ignore - some issue with @tscircuit/soup union type
|
|
1191
1246
|
outer_diameter: props.outerDiameter,
|
|
1192
1247
|
hole_diameter: props.holeDiameter,
|
|
1193
1248
|
shape: "circle",
|
|
1194
1249
|
port_hints: this.getNameAndAliases(),
|
|
1195
1250
|
x: position.x,
|
|
1196
1251
|
y: position.y,
|
|
1197
|
-
|
|
1198
|
-
};
|
|
1199
|
-
|
|
1252
|
+
layers: ["top", "bottom"]
|
|
1253
|
+
});
|
|
1254
|
+
this.pcb_plated_hole_id = pcb_plated_hole.pcb_plated_hole_id;
|
|
1200
1255
|
}
|
|
1201
1256
|
}
|
|
1202
1257
|
};
|
|
@@ -2921,6 +2976,58 @@ var Constraint2 = class extends PrimitiveComponent {
|
|
|
2921
2976
|
}
|
|
2922
2977
|
};
|
|
2923
2978
|
|
|
2979
|
+
// lib/components/primitive-components/Hole.ts
|
|
2980
|
+
import { holeProps } from "@tscircuit/props";
|
|
2981
|
+
var Hole = class extends PrimitiveComponent {
|
|
2982
|
+
pcb_hole_id = null;
|
|
2983
|
+
isPcbPrimitive = true;
|
|
2984
|
+
get config() {
|
|
2985
|
+
return {
|
|
2986
|
+
zodProps: holeProps
|
|
2987
|
+
};
|
|
2988
|
+
}
|
|
2989
|
+
getPcbSize() {
|
|
2990
|
+
const { _parsedProps: props } = this;
|
|
2991
|
+
return { width: props.diameter, height: props.diameter };
|
|
2992
|
+
}
|
|
2993
|
+
doInitialPcbPrimitiveRender() {
|
|
2994
|
+
const { db } = this.root;
|
|
2995
|
+
const { _parsedProps: props } = this;
|
|
2996
|
+
const position = this._getGlobalPcbPositionBeforeLayout();
|
|
2997
|
+
const inserted_hole = db.pcb_hole.insert({
|
|
2998
|
+
hole_shape: "round",
|
|
2999
|
+
// @ts-ignore
|
|
3000
|
+
hole_diameter: props.diameter,
|
|
3001
|
+
x: position.x,
|
|
3002
|
+
y: position.y
|
|
3003
|
+
});
|
|
3004
|
+
this.pcb_hole_id = inserted_hole.pcb_hole_id;
|
|
3005
|
+
}
|
|
3006
|
+
_getCircuitJsonBounds() {
|
|
3007
|
+
const { db } = this.root;
|
|
3008
|
+
const hole = db.pcb_hole.get(this.pcb_hole_id);
|
|
3009
|
+
const size = this.getPcbSize();
|
|
3010
|
+
return {
|
|
3011
|
+
center: { x: hole.x, y: hole.y },
|
|
3012
|
+
bounds: {
|
|
3013
|
+
left: hole.x - size.width / 2,
|
|
3014
|
+
top: hole.y - size.height / 2,
|
|
3015
|
+
right: hole.x + size.width / 2,
|
|
3016
|
+
bottom: hole.y + size.height / 2
|
|
3017
|
+
},
|
|
3018
|
+
width: size.width,
|
|
3019
|
+
height: size.height
|
|
3020
|
+
};
|
|
3021
|
+
}
|
|
3022
|
+
_setPositionFromLayout(newCenter) {
|
|
3023
|
+
const { db } = this.root;
|
|
3024
|
+
db.pcb_hole.update(this.pcb_hole_id, {
|
|
3025
|
+
x: newCenter.x,
|
|
3026
|
+
y: newCenter.y
|
|
3027
|
+
});
|
|
3028
|
+
}
|
|
3029
|
+
};
|
|
3030
|
+
|
|
2924
3031
|
// lib/Project.ts
|
|
2925
3032
|
import { su } from "@tscircuit/soup-util";
|
|
2926
3033
|
import { isValidElement as isValidElement2 } from "react";
|
|
@@ -3027,6 +3134,7 @@ export {
|
|
|
3027
3134
|
Constraint2 as Constraint,
|
|
3028
3135
|
Footprint,
|
|
3029
3136
|
Group,
|
|
3137
|
+
Hole,
|
|
3030
3138
|
Jumper,
|
|
3031
3139
|
Led,
|
|
3032
3140
|
Net,
|
package/lib/components/index.ts
CHANGED
|
@@ -17,3 +17,4 @@ export { Jumper } from "./normal-components/Jumper"
|
|
|
17
17
|
export { SilkscreenPath } from "./primitive-components/SilkscreenPath"
|
|
18
18
|
export { PlatedHole } from "./primitive-components/PlatedHole"
|
|
19
19
|
export { Constraint } from "./primitive-components/Constraint"
|
|
20
|
+
export { Hole } from "./primitive-components/Hole"
|
|
@@ -39,6 +39,7 @@ export class Footprint extends PrimitiveComponent<typeof footprintProps> {
|
|
|
39
39
|
function getKVar(name: string) {
|
|
40
40
|
if (!(name in kVars)) {
|
|
41
41
|
kVars[name] = new kiwi.Variable(name)
|
|
42
|
+
solver.addEditVariable(kVars[name], kiwi.Strength.weak)
|
|
42
43
|
}
|
|
43
44
|
return kVars[name]
|
|
44
45
|
}
|
|
@@ -47,8 +48,6 @@ export class Footprint extends PrimitiveComponent<typeof footprintProps> {
|
|
|
47
48
|
for (const { selector, bounds } of involvedComponents) {
|
|
48
49
|
const kvx = getKVar(`${selector}_x`)
|
|
49
50
|
const kvy = getKVar(`${selector}_y`)
|
|
50
|
-
solver.addEditVariable(kvx, kiwi.Strength.weak)
|
|
51
|
-
solver.addEditVariable(kvy, kiwi.Strength.weak)
|
|
52
51
|
solver.suggestValue(kvx, bounds.center.x)
|
|
53
52
|
solver.suggestValue(kvy, bounds.center.y)
|
|
54
53
|
}
|
|
@@ -77,10 +76,10 @@ export class Footprint extends PrimitiveComponent<typeof footprintProps> {
|
|
|
77
76
|
)
|
|
78
77
|
} else if (edgeToEdge) {
|
|
79
78
|
// rightEdge - leftEdge = xdist
|
|
80
|
-
// right
|
|
79
|
+
// right - rightBounds.width/2 - left - leftBounds.width/2 = xdist
|
|
81
80
|
const expr = new kiwi.Expression(
|
|
82
81
|
rightVar,
|
|
83
|
-
rightBounds.width / 2,
|
|
82
|
+
-rightBounds.width / 2,
|
|
84
83
|
[-1, leftVar],
|
|
85
84
|
-leftBounds.width / 2,
|
|
86
85
|
)
|
|
@@ -93,69 +92,107 @@ export class Footprint extends PrimitiveComponent<typeof footprintProps> {
|
|
|
93
92
|
),
|
|
94
93
|
)
|
|
95
94
|
}
|
|
96
|
-
}
|
|
95
|
+
} else if ("ydist" in props) {
|
|
96
|
+
const { ydist, top, bottom, edgeToEdge, centerToCenter } = props
|
|
97
|
+
const topVar = getKVar(`${top}_y`)
|
|
98
|
+
const bottomVar = getKVar(`${bottom}_y`)
|
|
99
|
+
const topBounds = getComponentDetails(top)?.bounds!
|
|
100
|
+
const bottomBounds = getComponentDetails(bottom)?.bounds!
|
|
97
101
|
|
|
98
|
-
|
|
99
|
-
solver.updateVariables()
|
|
100
|
-
if (debug.enabled) {
|
|
101
|
-
console.log("Solution to layout constraints:")
|
|
102
|
-
console.table(
|
|
103
|
-
Object.entries(kVars).map(([key, kvar]) => ({
|
|
104
|
-
var: key,
|
|
105
|
-
val: kvar.value(),
|
|
106
|
-
})),
|
|
107
|
-
)
|
|
108
|
-
}
|
|
102
|
+
// Top - Bottom = ydist
|
|
109
103
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
bounds.right = Math.max(bounds.right, newRight)
|
|
140
|
-
bounds.top = Math.max(bounds.top, newTop)
|
|
141
|
-
bounds.bottom = Math.min(bounds.bottom, newBottom)
|
|
104
|
+
if (centerToCenter) {
|
|
105
|
+
// top - bottom = ydist
|
|
106
|
+
const expr = new kiwi.Expression(topVar, [-1, bottomVar])
|
|
107
|
+
solver.addConstraint(
|
|
108
|
+
new kiwi.Constraint(
|
|
109
|
+
expr,
|
|
110
|
+
kiwi.Operator.Eq,
|
|
111
|
+
props.ydist,
|
|
112
|
+
kiwi.Strength.required,
|
|
113
|
+
),
|
|
114
|
+
)
|
|
115
|
+
} else if (edgeToEdge) {
|
|
116
|
+
// topElmBottomEdge - bottomElmTopEdge = ydist
|
|
117
|
+
// topElmCenterY - topElmHeight/2 - bottomElmCenterY - bottomElmHeight/2 = ydist
|
|
118
|
+
const expr = new kiwi.Expression(
|
|
119
|
+
topVar,
|
|
120
|
+
topBounds.height / 2,
|
|
121
|
+
[-1, bottomVar],
|
|
122
|
+
-bottomBounds.height / 2,
|
|
123
|
+
)
|
|
124
|
+
solver.addConstraint(
|
|
125
|
+
new kiwi.Constraint(
|
|
126
|
+
expr,
|
|
127
|
+
kiwi.Operator.Eq,
|
|
128
|
+
props.ydist,
|
|
129
|
+
kiwi.Strength.required,
|
|
130
|
+
),
|
|
131
|
+
)
|
|
132
|
+
}
|
|
142
133
|
}
|
|
134
|
+
}
|
|
143
135
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
136
|
+
// 3. Solve the system of equations
|
|
137
|
+
solver.updateVariables()
|
|
138
|
+
if (debug.enabled) {
|
|
139
|
+
console.log("Solution to layout constraints:")
|
|
140
|
+
console.table(
|
|
141
|
+
Object.entries(kVars).map(([key, kvar]) => ({
|
|
142
|
+
var: key,
|
|
143
|
+
val: kvar.value(),
|
|
144
|
+
})),
|
|
145
|
+
)
|
|
146
|
+
}
|
|
149
147
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
148
|
+
// 3.1 Compute the global offset. There are different ways to do this:
|
|
149
|
+
// - If any component has a fixed position, then that can be used as the
|
|
150
|
+
// origin to determine the offset of all other components
|
|
151
|
+
// - If no component has a fixed position, then we recenter everything
|
|
152
|
+
// using the new bounds of all the involved components
|
|
153
|
+
|
|
154
|
+
// TODO determine if there's a fixed component
|
|
155
|
+
|
|
156
|
+
// Determine the new bounds all the involved components and compute the
|
|
157
|
+
// bounds of this footprint
|
|
158
|
+
const bounds = {
|
|
159
|
+
left: Infinity,
|
|
160
|
+
right: -Infinity,
|
|
161
|
+
top: -Infinity,
|
|
162
|
+
bottom: Infinity,
|
|
163
|
+
}
|
|
164
|
+
for (const {
|
|
165
|
+
selector,
|
|
166
|
+
bounds: { width, height },
|
|
167
|
+
} of involvedComponents) {
|
|
168
|
+
const kvx = getKVar(`${selector}_x`)
|
|
169
|
+
const kvy = getKVar(`${selector}_y`)
|
|
170
|
+
|
|
171
|
+
const newLeft = kvx.value() - width / 2
|
|
172
|
+
const newRight = kvx.value() + width / 2
|
|
173
|
+
const newTop = kvy.value() + height / 2
|
|
174
|
+
const newBottom = kvy.value() - height / 2
|
|
175
|
+
|
|
176
|
+
bounds.left = Math.min(bounds.left, newLeft)
|
|
177
|
+
bounds.right = Math.max(bounds.right, newRight)
|
|
178
|
+
bounds.top = Math.max(bounds.top, newTop)
|
|
179
|
+
bounds.bottom = Math.min(bounds.bottom, newBottom)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Compute the global offset, we can use this to recenter each component
|
|
183
|
+
const globalOffset = {
|
|
184
|
+
x: -(bounds.right + bounds.left) / 2,
|
|
185
|
+
y: -(bounds.top + bounds.bottom) / 2,
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// 4. Update the component positions
|
|
189
|
+
for (const { component, selector } of involvedComponents) {
|
|
190
|
+
const kvx = getKVar(`${selector}_x`)
|
|
191
|
+
const kvy = getKVar(`${selector}_y`)
|
|
192
|
+
component._setPositionFromLayout({
|
|
193
|
+
x: kvx.value() + globalOffset.x,
|
|
194
|
+
y: kvy.value() + globalOffset.y,
|
|
195
|
+
})
|
|
159
196
|
}
|
|
160
197
|
}
|
|
161
198
|
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { PrimitiveComponent } from "../base-components/PrimitiveComponent"
|
|
2
|
+
import { holeProps } from "@tscircuit/props"
|
|
3
|
+
import type { PCBHole } from "@tscircuit/soup"
|
|
4
|
+
|
|
5
|
+
export class Hole extends PrimitiveComponent<typeof holeProps> {
|
|
6
|
+
pcb_hole_id: string | null = null
|
|
7
|
+
isPcbPrimitive = true
|
|
8
|
+
|
|
9
|
+
get config() {
|
|
10
|
+
return {
|
|
11
|
+
zodProps: holeProps,
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
getPcbSize(): { width: number; height: number } {
|
|
16
|
+
const { _parsedProps: props } = this
|
|
17
|
+
return { width: props.diameter, height: props.diameter }
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
doInitialPcbPrimitiveRender(): void {
|
|
21
|
+
const { db } = this.root!
|
|
22
|
+
const { _parsedProps: props } = this
|
|
23
|
+
const position = this._getGlobalPcbPositionBeforeLayout()
|
|
24
|
+
|
|
25
|
+
const inserted_hole = db.pcb_hole.insert({
|
|
26
|
+
hole_shape: "round",
|
|
27
|
+
// @ts-ignore
|
|
28
|
+
hole_diameter: props.diameter,
|
|
29
|
+
x: position.x,
|
|
30
|
+
y: position.y,
|
|
31
|
+
})
|
|
32
|
+
this.pcb_hole_id = inserted_hole.pcb_hole_id!
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
_getCircuitJsonBounds(): {
|
|
36
|
+
center: { x: number; y: number }
|
|
37
|
+
bounds: { left: number; top: number; right: number; bottom: number }
|
|
38
|
+
width: number
|
|
39
|
+
height: number
|
|
40
|
+
} {
|
|
41
|
+
const { db } = this.root!
|
|
42
|
+
const hole = db.pcb_hole.get(this.pcb_hole_id!)!
|
|
43
|
+
const size = this.getPcbSize()
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
center: { x: hole.x, y: hole.y },
|
|
47
|
+
bounds: {
|
|
48
|
+
left: hole.x - size.width / 2,
|
|
49
|
+
top: hole.y - size.height / 2,
|
|
50
|
+
right: hole.x + size.width / 2,
|
|
51
|
+
bottom: hole.y + size.height / 2,
|
|
52
|
+
},
|
|
53
|
+
width: size.width,
|
|
54
|
+
height: size.height,
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
_setPositionFromLayout(newCenter: { x: number; y: number }) {
|
|
59
|
+
const { db } = this.root!
|
|
60
|
+
db.pcb_hole.update(this.pcb_hole_id!, {
|
|
61
|
+
x: newCenter.x,
|
|
62
|
+
y: newCenter.y,
|
|
63
|
+
})
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -27,6 +27,37 @@ export class PlatedHole extends PrimitiveComponent<typeof platedHoleProps> {
|
|
|
27
27
|
)
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
_getCircuitJsonBounds(): {
|
|
31
|
+
center: { x: number; y: number }
|
|
32
|
+
bounds: { left: number; top: number; right: number; bottom: number }
|
|
33
|
+
width: number
|
|
34
|
+
height: number
|
|
35
|
+
} {
|
|
36
|
+
const { db } = this.root!
|
|
37
|
+
const platedHole = db.pcb_plated_hole.get(this.pcb_plated_hole_id!)!
|
|
38
|
+
const size = this.getPcbSize()
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
center: { x: platedHole.x, y: platedHole.y },
|
|
42
|
+
bounds: {
|
|
43
|
+
left: platedHole.x - size.width / 2,
|
|
44
|
+
top: platedHole.y - size.height / 2,
|
|
45
|
+
right: platedHole.x + size.width / 2,
|
|
46
|
+
bottom: platedHole.y + size.height / 2,
|
|
47
|
+
},
|
|
48
|
+
width: size.width,
|
|
49
|
+
height: size.height,
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
_setPositionFromLayout(newCenter: { x: number; y: number }) {
|
|
54
|
+
const { db } = this.root!
|
|
55
|
+
db.pcb_plated_hole.update(this.pcb_plated_hole_id!, {
|
|
56
|
+
x: newCenter.x,
|
|
57
|
+
y: newCenter.y,
|
|
58
|
+
})
|
|
59
|
+
}
|
|
60
|
+
|
|
30
61
|
doInitialPortMatching(): void {
|
|
31
62
|
const parentPorts = (this.parent?.children ?? []).filter(
|
|
32
63
|
(c) => c.componentName === "Port",
|
|
@@ -51,23 +82,20 @@ export class PlatedHole extends PrimitiveComponent<typeof platedHoleProps> {
|
|
|
51
82
|
if (!props.portHints) return
|
|
52
83
|
const position = this._getGlobalPcbPositionBeforeLayout()
|
|
53
84
|
if (props.shape === "circle") {
|
|
54
|
-
const
|
|
85
|
+
const pcb_plated_hole = db.pcb_plated_hole.insert({
|
|
55
86
|
pcb_component_id: this.parent?.pcb_component_id!,
|
|
56
87
|
pcb_port_id: this.matchedPort?.pcb_port_id!,
|
|
57
|
-
|
|
88
|
+
// @ts-ignore - some issue with @tscircuit/soup union type
|
|
58
89
|
outer_diameter: props.outerDiameter,
|
|
59
90
|
hole_diameter: props.holeDiameter,
|
|
60
|
-
shape: "circle",
|
|
91
|
+
shape: "circle" as const,
|
|
61
92
|
port_hints: this.getNameAndAliases(),
|
|
62
93
|
x: position.x,
|
|
63
94
|
y: position.y,
|
|
64
|
-
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// @ts-ignore - some issue with soup-util types it seems
|
|
68
|
-
const pcb_plated_hole = db.pcb_plated_hole.insert(plated_hole_input)
|
|
95
|
+
layers: ["top", "bottom"],
|
|
96
|
+
})
|
|
69
97
|
|
|
70
|
-
|
|
98
|
+
this.pcb_plated_hole_id = pcb_plated_hole.pcb_plated_hole_id
|
|
71
99
|
}
|
|
72
100
|
}
|
|
73
101
|
}
|
|
@@ -1,21 +1,23 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { SchematicPinStyle } from "@tscircuit/props"
|
|
2
2
|
import { schematic_component } from "@tscircuit/soup"
|
|
3
3
|
import { z } from "zod"
|
|
4
4
|
|
|
5
5
|
type UnderscorePinStyles = z.input<typeof schematic_component>["pin_styles"]
|
|
6
6
|
|
|
7
7
|
export const underscorifyPinStyles = (
|
|
8
|
-
pinStyles:
|
|
8
|
+
pinStyles: Record<string, SchematicPinStyle> | undefined,
|
|
9
9
|
): UnderscorePinStyles | undefined => {
|
|
10
10
|
if (!pinStyles) return undefined
|
|
11
11
|
const underscorePinStyles: UnderscorePinStyles = {}
|
|
12
12
|
|
|
13
|
-
for (const [pinName, pinStyle] of Object.entries(pinStyles)
|
|
13
|
+
for (const [pinName, pinStyle] of Object.entries(pinStyles) as Array<
|
|
14
|
+
[string, SchematicPinStyle]
|
|
15
|
+
>) {
|
|
14
16
|
underscorePinStyles[pinName] = {
|
|
15
|
-
bottom_margin: pinStyle.bottomMargin,
|
|
16
|
-
left_margin: pinStyle.leftMargin,
|
|
17
|
-
right_margin: pinStyle.rightMargin,
|
|
18
|
-
top_margin: pinStyle.topMargin,
|
|
17
|
+
bottom_margin: pinStyle.bottomMargin as number,
|
|
18
|
+
left_margin: pinStyle.leftMargin as number,
|
|
19
|
+
right_margin: pinStyle.rightMargin as number,
|
|
20
|
+
top_margin: pinStyle.topMargin as number,
|
|
19
21
|
}
|
|
20
22
|
}
|
|
21
23
|
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@tscircuit/core",
|
|
3
3
|
"module": "index.ts",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"version": "0.0.
|
|
5
|
+
"version": "0.0.33",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"main": "dist/index.js",
|
|
8
8
|
"files": [
|
|
@@ -35,8 +35,8 @@
|
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"@lume/kiwi": "^0.4.3",
|
|
37
37
|
"@tscircuit/infgrid-ijump-astar": "^0.0.6",
|
|
38
|
-
"@tscircuit/props": "^0.0.
|
|
39
|
-
"@tscircuit/soup": "^0.0.
|
|
38
|
+
"@tscircuit/props": "^0.0.61",
|
|
39
|
+
"@tscircuit/soup": "^0.0.66",
|
|
40
40
|
"@tscircuit/soup-util": "0.0.18",
|
|
41
41
|
"footprinter": "^0.0.44",
|
|
42
42
|
"react": "^18.3.1",
|