@tscircuit/core 0.0.32 → 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 +68 -4
- package/dist/index.js +136 -59
- package/lib/components/primitive-components/Footprint.ts +99 -62
- package/lib/components/primitive-components/Hole.ts +35 -6
- 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
|
@@ -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
|
}
|
|
@@ -3503,7 +3527,7 @@ declare class Hole extends PrimitiveComponent<typeof holeProps> {
|
|
|
3503
3527
|
pcb_hole_id: string | null;
|
|
3504
3528
|
isPcbPrimitive: boolean;
|
|
3505
3529
|
get config(): {
|
|
3506
|
-
zodProps: zod.ZodObject<zod.objectUtil.extendShape<Omit<{
|
|
3530
|
+
zodProps: zod.ZodEffects<zod.ZodObject<zod.objectUtil.extendShape<Omit<{
|
|
3507
3531
|
pcbX: zod.ZodOptional<zod.ZodEffects<zod.ZodUnion<[zod.ZodString, zod.ZodNumber]>, number, string | number>>;
|
|
3508
3532
|
pcbY: zod.ZodOptional<zod.ZodEffects<zod.ZodUnion<[zod.ZodString, zod.ZodNumber]>, number, string | number>>;
|
|
3509
3533
|
pcbRotation: zod.ZodOptional<zod.ZodEffects<zod.ZodUnion<[zod.ZodString, zod.ZodNumber]>, number, string | number>>;
|
|
@@ -3517,19 +3541,41 @@ declare class Hole extends PrimitiveComponent<typeof holeProps> {
|
|
|
3517
3541
|
name: "top" | "bottom" | "inner1" | "inner2" | "inner3" | "inner4" | "inner5" | "inner6";
|
|
3518
3542
|
}>>;
|
|
3519
3543
|
}, "pcbRotation">, {
|
|
3520
|
-
|
|
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>>;
|
|
3521
3547
|
}>, "strip", zod.ZodTypeAny, {
|
|
3522
|
-
holeDiameter: number;
|
|
3523
3548
|
pcbX?: number | undefined;
|
|
3524
3549
|
pcbY?: number | undefined;
|
|
3525
3550
|
layer?: "top" | "bottom" | "inner1" | "inner2" | "inner3" | "inner4" | "inner5" | "inner6" | undefined;
|
|
3551
|
+
name?: string | undefined;
|
|
3552
|
+
radius?: number | undefined;
|
|
3553
|
+
diameter?: number | undefined;
|
|
3526
3554
|
}, {
|
|
3527
|
-
holeDiameter: string | number;
|
|
3528
3555
|
pcbX?: string | number | undefined;
|
|
3529
3556
|
pcbY?: string | number | undefined;
|
|
3530
3557
|
layer?: "top" | "bottom" | "inner1" | "inner2" | "inner3" | "inner4" | "inner5" | "inner6" | {
|
|
3531
3558
|
name: "top" | "bottom" | "inner1" | "inner2" | "inner3" | "inner4" | "inner5" | "inner6";
|
|
3532
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;
|
|
3533
3579
|
}>;
|
|
3534
3580
|
};
|
|
3535
3581
|
getPcbSize(): {
|
|
@@ -3537,6 +3583,24 @@ declare class Hole extends PrimitiveComponent<typeof holeProps> {
|
|
|
3537
3583
|
height: number;
|
|
3538
3584
|
};
|
|
3539
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;
|
|
3540
3604
|
}
|
|
3541
3605
|
|
|
3542
3606
|
declare global {
|
package/dist/index.js
CHANGED
|
@@ -535,16 +535,15 @@ var Footprint = class extends PrimitiveComponent {
|
|
|
535
535
|
function getKVar(name) {
|
|
536
536
|
if (!(name in kVars)) {
|
|
537
537
|
kVars[name] = new kiwi.Variable(name);
|
|
538
|
+
solver.addEditVariable(kVars[name], kiwi.Strength.weak);
|
|
538
539
|
}
|
|
539
540
|
return kVars[name];
|
|
540
541
|
}
|
|
541
|
-
for (const { selector, bounds } of involvedComponents) {
|
|
542
|
+
for (const { selector, bounds: bounds2 } of involvedComponents) {
|
|
542
543
|
const kvx = getKVar(`${selector}_x`);
|
|
543
544
|
const kvy = getKVar(`${selector}_y`);
|
|
544
|
-
solver.
|
|
545
|
-
solver.
|
|
546
|
-
solver.suggestValue(kvx, bounds.center.x);
|
|
547
|
-
solver.suggestValue(kvy, bounds.center.y);
|
|
545
|
+
solver.suggestValue(kvx, bounds2.center.x);
|
|
546
|
+
solver.suggestValue(kvy, bounds2.center.y);
|
|
548
547
|
}
|
|
549
548
|
for (const constraint of constraints) {
|
|
550
549
|
const props = constraint._parsedProps;
|
|
@@ -567,7 +566,7 @@ var Footprint = class extends PrimitiveComponent {
|
|
|
567
566
|
} else if (edgeToEdge) {
|
|
568
567
|
const expr = new kiwi.Expression(
|
|
569
568
|
rightVar,
|
|
570
|
-
rightBounds.width / 2,
|
|
569
|
+
-rightBounds.width / 2,
|
|
571
570
|
[-1, leftVar],
|
|
572
571
|
-leftBounds.width / 2
|
|
573
572
|
);
|
|
@@ -580,50 +579,82 @@ var Footprint = class extends PrimitiveComponent {
|
|
|
580
579
|
)
|
|
581
580
|
);
|
|
582
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
|
+
}
|
|
583
614
|
}
|
|
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
|
-
|
|
626
|
-
}
|
|
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
|
+
});
|
|
627
658
|
}
|
|
628
659
|
}
|
|
629
660
|
};
|
|
@@ -1164,6 +1195,29 @@ var PlatedHole = class extends PrimitiveComponent {
|
|
|
1164
1195
|
`getPcbSize for shape "${props.shape}" not implemented for ${this.componentName}`
|
|
1165
1196
|
);
|
|
1166
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
|
+
}
|
|
1167
1221
|
doInitialPortMatching() {
|
|
1168
1222
|
const parentPorts = (this.parent?.children ?? []).filter(
|
|
1169
1223
|
(c) => c.componentName === "Port"
|
|
@@ -1185,19 +1239,19 @@ var PlatedHole = class extends PrimitiveComponent {
|
|
|
1185
1239
|
if (!props.portHints) return;
|
|
1186
1240
|
const position = this._getGlobalPcbPositionBeforeLayout();
|
|
1187
1241
|
if (props.shape === "circle") {
|
|
1188
|
-
const
|
|
1242
|
+
const pcb_plated_hole = db.pcb_plated_hole.insert({
|
|
1189
1243
|
pcb_component_id: this.parent?.pcb_component_id,
|
|
1190
1244
|
pcb_port_id: this.matchedPort?.pcb_port_id,
|
|
1191
|
-
|
|
1245
|
+
// @ts-ignore - some issue with @tscircuit/soup union type
|
|
1192
1246
|
outer_diameter: props.outerDiameter,
|
|
1193
1247
|
hole_diameter: props.holeDiameter,
|
|
1194
1248
|
shape: "circle",
|
|
1195
1249
|
port_hints: this.getNameAndAliases(),
|
|
1196
1250
|
x: position.x,
|
|
1197
1251
|
y: position.y,
|
|
1198
|
-
|
|
1199
|
-
};
|
|
1200
|
-
|
|
1252
|
+
layers: ["top", "bottom"]
|
|
1253
|
+
});
|
|
1254
|
+
this.pcb_plated_hole_id = pcb_plated_hole.pcb_plated_hole_id;
|
|
1201
1255
|
}
|
|
1202
1256
|
}
|
|
1203
1257
|
};
|
|
@@ -2934,20 +2988,43 @@ var Hole = class extends PrimitiveComponent {
|
|
|
2934
2988
|
}
|
|
2935
2989
|
getPcbSize() {
|
|
2936
2990
|
const { _parsedProps: props } = this;
|
|
2937
|
-
return { width: props.
|
|
2991
|
+
return { width: props.diameter, height: props.diameter };
|
|
2938
2992
|
}
|
|
2939
2993
|
doInitialPcbPrimitiveRender() {
|
|
2940
2994
|
const { db } = this.root;
|
|
2941
2995
|
const { _parsedProps: props } = this;
|
|
2942
2996
|
const position = this._getGlobalPcbPositionBeforeLayout();
|
|
2943
|
-
const
|
|
2944
|
-
type: "pcb_hole",
|
|
2997
|
+
const inserted_hole = db.pcb_hole.insert({
|
|
2945
2998
|
hole_shape: "round",
|
|
2946
|
-
|
|
2999
|
+
// @ts-ignore
|
|
3000
|
+
hole_diameter: props.diameter,
|
|
2947
3001
|
x: position.x,
|
|
2948
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
|
|
2949
3020
|
};
|
|
2950
|
-
|
|
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
|
+
});
|
|
2951
3028
|
}
|
|
2952
3029
|
};
|
|
2953
3030
|
|
|
@@ -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
|
}
|
|
@@ -14,7 +14,7 @@ export class Hole extends PrimitiveComponent<typeof holeProps> {
|
|
|
14
14
|
|
|
15
15
|
getPcbSize(): { width: number; height: number } {
|
|
16
16
|
const { _parsedProps: props } = this
|
|
17
|
-
return { width: props.
|
|
17
|
+
return { width: props.diameter, height: props.diameter }
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
doInitialPcbPrimitiveRender(): void {
|
|
@@ -22,15 +22,44 @@ export class Hole extends PrimitiveComponent<typeof holeProps> {
|
|
|
22
22
|
const { _parsedProps: props } = this
|
|
23
23
|
const position = this._getGlobalPcbPositionBeforeLayout()
|
|
24
24
|
|
|
25
|
-
const
|
|
26
|
-
type: "pcb_hole",
|
|
25
|
+
const inserted_hole = db.pcb_hole.insert({
|
|
27
26
|
hole_shape: "round",
|
|
28
|
-
|
|
27
|
+
// @ts-ignore
|
|
28
|
+
hole_diameter: props.diameter,
|
|
29
29
|
x: position.x,
|
|
30
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,
|
|
31
55
|
}
|
|
56
|
+
}
|
|
32
57
|
|
|
33
|
-
|
|
34
|
-
|
|
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
|
+
})
|
|
35
64
|
}
|
|
36
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",
|