@tscircuit/core 0.0.30 → 0.0.31
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 +200 -51
- package/dist/index.js +276 -41
- package/lib/Project.ts +4 -1
- package/lib/components/base-components/NormalComponent.ts +4 -2
- package/lib/components/base-components/PrimitiveComponent.ts +58 -8
- package/lib/components/base-components/Renderable.ts +4 -3
- package/lib/components/index.ts +1 -0
- package/lib/components/normal-components/Board.ts +1 -1
- package/lib/components/primitive-components/Constraint.ts +49 -0
- package/lib/components/primitive-components/Footprint.ts +158 -1
- package/lib/components/primitive-components/Net.ts +2 -2
- package/lib/components/primitive-components/PlatedHole.ts +1 -1
- package/lib/components/primitive-components/Port.ts +8 -13
- package/lib/components/primitive-components/SilkscreenPath.ts +1 -1
- package/lib/components/primitive-components/SmtPad.ts +54 -4
- package/lib/components/primitive-components/Trace.ts +2 -2
- package/lib/components/primitive-components/TraceHint.ts +1 -1
- package/lib/fiber/intrinsic-jsx.ts +2 -0
- package/lib/utils/getClosest.ts +9 -3
- package/package.json +5 -2
package/dist/index.js
CHANGED
|
@@ -10,6 +10,7 @@ __export(components_exports, {
|
|
|
10
10
|
Board: () => Board,
|
|
11
11
|
Capacitor: () => Capacitor,
|
|
12
12
|
Chip: () => Chip,
|
|
13
|
+
Constraint: () => Constraint2,
|
|
13
14
|
Footprint: () => Footprint,
|
|
14
15
|
Group: () => Group,
|
|
15
16
|
Jumper: () => Jumper,
|
|
@@ -36,14 +37,12 @@ import "react";
|
|
|
36
37
|
import "react";
|
|
37
38
|
var orderedRenderPhases = [
|
|
38
39
|
"ReactSubtreesRender",
|
|
39
|
-
// probably going to be removed b/c subtrees should render instantly
|
|
40
40
|
"InitializePortsFromChildren",
|
|
41
41
|
"CreateNetsFromProps",
|
|
42
42
|
"CreateTracesFromProps",
|
|
43
43
|
"SourceRender",
|
|
44
44
|
"SourceParentAttachment",
|
|
45
45
|
"PortDiscovery",
|
|
46
|
-
// probably going to be removed b/c port discovery can always be done on prop change
|
|
47
46
|
"PortMatching",
|
|
48
47
|
"SourceTraceRender",
|
|
49
48
|
"SchematicComponentRender",
|
|
@@ -51,8 +50,9 @@ var orderedRenderPhases = [
|
|
|
51
50
|
"SchematicPortRender",
|
|
52
51
|
"SchematicTraceRender",
|
|
53
52
|
"PcbComponentRender",
|
|
54
|
-
"PcbPortRender",
|
|
55
53
|
"PcbPrimitiveRender",
|
|
54
|
+
"PcbFootprintLayout",
|
|
55
|
+
"PcbPortRender",
|
|
56
56
|
"PcbParentAttachment",
|
|
57
57
|
"PcbLayout",
|
|
58
58
|
"PcbTraceRender",
|
|
@@ -185,6 +185,17 @@ var PrimitiveComponent = class extends Renderable {
|
|
|
185
185
|
return Boolean(this.props.subcircuit) || // Implied opaque group for top-level group
|
|
186
186
|
this.lowercaseComponentName === "group" && this?.parent?.isRoot;
|
|
187
187
|
}
|
|
188
|
+
/**
|
|
189
|
+
* A primitive container is a component that contains one or more ports and
|
|
190
|
+
* primitive components that are designed to interact.
|
|
191
|
+
*
|
|
192
|
+
* For example a resistor contains ports and smtpads that interact, so the
|
|
193
|
+
* resistor is a primitive container. Inside a primitive container, the ports
|
|
194
|
+
* and pads are likely to reference each other and look for eachother during
|
|
195
|
+
* the port matching phase.
|
|
196
|
+
*
|
|
197
|
+
*/
|
|
198
|
+
isPrimitiveContainer = false;
|
|
188
199
|
source_group_id = null;
|
|
189
200
|
source_component_id = null;
|
|
190
201
|
schematic_component_id = null;
|
|
@@ -236,14 +247,14 @@ var PrimitiveComponent = class extends Renderable {
|
|
|
236
247
|
* components, including this component's translation and rotation.
|
|
237
248
|
*
|
|
238
249
|
* This is used to compute this component's position as well as all children
|
|
239
|
-
* components positions
|
|
250
|
+
* components positions before layout is applied
|
|
240
251
|
*/
|
|
241
|
-
|
|
252
|
+
_computePcbGlobalTransformBeforeLayout() {
|
|
242
253
|
const { _parsedProps: props } = this;
|
|
243
254
|
const manualPlacement = this.getSubcircuit()._getManualPlacementForComponent(this);
|
|
244
255
|
if (manualPlacement && this.props.pcbX === void 0 && this.props.pcbY === void 0) {
|
|
245
256
|
return compose(
|
|
246
|
-
this.parent?.
|
|
257
|
+
this.parent?._computePcbGlobalTransformBeforeLayout() ?? identity(),
|
|
247
258
|
compose(
|
|
248
259
|
translate(manualPlacement.x, manualPlacement.y),
|
|
249
260
|
rotate((props.pcbRotation ?? 0) * Math.PI / 180)
|
|
@@ -251,10 +262,37 @@ var PrimitiveComponent = class extends Renderable {
|
|
|
251
262
|
);
|
|
252
263
|
}
|
|
253
264
|
return compose(
|
|
254
|
-
this.parent?.
|
|
265
|
+
this.parent?._computePcbGlobalTransformBeforeLayout() ?? identity(),
|
|
255
266
|
this.computePcbPropsTransform()
|
|
256
267
|
);
|
|
257
268
|
}
|
|
269
|
+
getPrimitiveContainer() {
|
|
270
|
+
if (this.isPrimitiveContainer) return this;
|
|
271
|
+
return this.parent?.getPrimitiveContainer?.() ?? null;
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Compute the bounds of this component the circuit json elements associated
|
|
275
|
+
* with it.
|
|
276
|
+
*/
|
|
277
|
+
_getCircuitJsonBounds() {
|
|
278
|
+
return {
|
|
279
|
+
center: { x: 0, y: 0 },
|
|
280
|
+
bounds: { left: 0, top: 0, right: 0, bottom: 0 },
|
|
281
|
+
width: 0,
|
|
282
|
+
height: 0
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Set the position of this component from the layout solver. This method
|
|
287
|
+
* should operate using CircuitJson associated with this component, like
|
|
288
|
+
* _getCircuitJsonBounds it can be called multiple times as different
|
|
289
|
+
* parents apply layout to their children.
|
|
290
|
+
*/
|
|
291
|
+
_setPositionFromLayout(newCenter) {
|
|
292
|
+
throw new Error(
|
|
293
|
+
`_setPositionFromLayout not implemented for ${this.componentName}`
|
|
294
|
+
);
|
|
295
|
+
}
|
|
258
296
|
/**
|
|
259
297
|
* Computes a transformation matrix from the props of this component for
|
|
260
298
|
* schematic components
|
|
@@ -295,7 +333,7 @@ var PrimitiveComponent = class extends Renderable {
|
|
|
295
333
|
for (const position of placementConfig.positions) {
|
|
296
334
|
if (isMatchingSelector(component, position.selector)) {
|
|
297
335
|
const center = applyToPoint(
|
|
298
|
-
this.
|
|
336
|
+
this._computePcbGlobalTransformBeforeLayout(),
|
|
299
337
|
position.center
|
|
300
338
|
);
|
|
301
339
|
return center;
|
|
@@ -303,10 +341,13 @@ var PrimitiveComponent = class extends Renderable {
|
|
|
303
341
|
}
|
|
304
342
|
return null;
|
|
305
343
|
}
|
|
306
|
-
|
|
307
|
-
return applyToPoint(this.
|
|
344
|
+
_getGlobalPcbPositionBeforeLayout() {
|
|
345
|
+
return applyToPoint(this._computePcbGlobalTransformBeforeLayout(), {
|
|
346
|
+
x: 0,
|
|
347
|
+
y: 0
|
|
348
|
+
});
|
|
308
349
|
}
|
|
309
|
-
|
|
350
|
+
_getGlobalSchematicPositionBeforeLayout() {
|
|
310
351
|
return applyToPoint(this.computeSchematicGlobalTransform(), { x: 0, y: 0 });
|
|
311
352
|
}
|
|
312
353
|
get root() {
|
|
@@ -465,7 +506,125 @@ var PrimitiveComponent = class extends Renderable {
|
|
|
465
506
|
};
|
|
466
507
|
|
|
467
508
|
// lib/components/primitive-components/Footprint.ts
|
|
509
|
+
import * as kiwi from "@lume/kiwi";
|
|
510
|
+
import Debug from "debug";
|
|
511
|
+
var debug = Debug("tscircuit:core:footprint");
|
|
468
512
|
var Footprint = class extends PrimitiveComponent {
|
|
513
|
+
/**
|
|
514
|
+
* A footprint is a constrainedlayout, the db elements are adjusted according
|
|
515
|
+
* to any constraints that are defined.
|
|
516
|
+
*/
|
|
517
|
+
doInitialPcbFootprintLayout() {
|
|
518
|
+
const constraints = this.children.filter(
|
|
519
|
+
(child) => child.componentName === "Constraint"
|
|
520
|
+
);
|
|
521
|
+
if (constraints.length === 0) return;
|
|
522
|
+
const involvedComponents = constraints.flatMap(
|
|
523
|
+
(constraint) => constraint._getAllReferencedComponents().componentsWithSelectors
|
|
524
|
+
).map(({ component, selector }) => ({
|
|
525
|
+
component,
|
|
526
|
+
selector,
|
|
527
|
+
bounds: component._getCircuitJsonBounds()
|
|
528
|
+
}));
|
|
529
|
+
function getComponentDetails(selector) {
|
|
530
|
+
return involvedComponents.find(({ selector: s }) => s === selector);
|
|
531
|
+
}
|
|
532
|
+
const solver = new kiwi.Solver();
|
|
533
|
+
const kVars = {};
|
|
534
|
+
function getKVar(name) {
|
|
535
|
+
if (!(name in kVars)) {
|
|
536
|
+
kVars[name] = new kiwi.Variable(name);
|
|
537
|
+
}
|
|
538
|
+
return kVars[name];
|
|
539
|
+
}
|
|
540
|
+
for (const { selector, bounds } of involvedComponents) {
|
|
541
|
+
const kvx = getKVar(`${selector}_x`);
|
|
542
|
+
const kvy = getKVar(`${selector}_y`);
|
|
543
|
+
solver.addEditVariable(kvx, kiwi.Strength.weak);
|
|
544
|
+
solver.addEditVariable(kvy, kiwi.Strength.weak);
|
|
545
|
+
solver.suggestValue(kvx, bounds.center.x);
|
|
546
|
+
solver.suggestValue(kvy, bounds.center.y);
|
|
547
|
+
}
|
|
548
|
+
for (const constraint of constraints) {
|
|
549
|
+
const props = constraint._parsedProps;
|
|
550
|
+
if ("xdist" in props) {
|
|
551
|
+
const { xdist, left, right, edgeToEdge, centerToCenter } = props;
|
|
552
|
+
const leftVar = getKVar(`${left}_x`);
|
|
553
|
+
const rightVar = getKVar(`${right}_x`);
|
|
554
|
+
const leftBounds = getComponentDetails(left)?.bounds;
|
|
555
|
+
const rightBounds = getComponentDetails(right)?.bounds;
|
|
556
|
+
if (centerToCenter) {
|
|
557
|
+
const expr = new kiwi.Expression(rightVar, [-1, leftVar]);
|
|
558
|
+
solver.addConstraint(
|
|
559
|
+
new kiwi.Constraint(
|
|
560
|
+
expr,
|
|
561
|
+
kiwi.Operator.Eq,
|
|
562
|
+
props.xdist,
|
|
563
|
+
kiwi.Strength.required
|
|
564
|
+
)
|
|
565
|
+
);
|
|
566
|
+
} else if (edgeToEdge) {
|
|
567
|
+
const expr = new kiwi.Expression(
|
|
568
|
+
rightVar,
|
|
569
|
+
rightBounds.width / 2,
|
|
570
|
+
[-1, leftVar],
|
|
571
|
+
-leftBounds.width / 2
|
|
572
|
+
);
|
|
573
|
+
solver.addConstraint(
|
|
574
|
+
new kiwi.Constraint(
|
|
575
|
+
expr,
|
|
576
|
+
kiwi.Operator.Eq,
|
|
577
|
+
props.xdist,
|
|
578
|
+
kiwi.Strength.required
|
|
579
|
+
)
|
|
580
|
+
);
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
solver.updateVariables();
|
|
584
|
+
if (debug.enabled) {
|
|
585
|
+
console.log("Solution to layout constraints:");
|
|
586
|
+
console.table(
|
|
587
|
+
Object.entries(kVars).map(([key, kvar]) => ({
|
|
588
|
+
var: key,
|
|
589
|
+
val: kvar.value()
|
|
590
|
+
}))
|
|
591
|
+
);
|
|
592
|
+
}
|
|
593
|
+
const bounds = {
|
|
594
|
+
left: Infinity,
|
|
595
|
+
right: -Infinity,
|
|
596
|
+
top: -Infinity,
|
|
597
|
+
bottom: Infinity
|
|
598
|
+
};
|
|
599
|
+
for (const {
|
|
600
|
+
selector,
|
|
601
|
+
bounds: { width, height }
|
|
602
|
+
} of involvedComponents) {
|
|
603
|
+
const kvx = getKVar(`${selector}_x`);
|
|
604
|
+
const kvy = getKVar(`${selector}_y`);
|
|
605
|
+
const newLeft = kvx.value() - width / 2;
|
|
606
|
+
const newRight = kvx.value() + width / 2;
|
|
607
|
+
const newTop = kvy.value() + height / 2;
|
|
608
|
+
const newBottom = kvy.value() - height / 2;
|
|
609
|
+
bounds.left = Math.min(bounds.left, newLeft);
|
|
610
|
+
bounds.right = Math.max(bounds.right, newRight);
|
|
611
|
+
bounds.top = Math.max(bounds.top, newTop);
|
|
612
|
+
bounds.bottom = Math.min(bounds.bottom, newBottom);
|
|
613
|
+
}
|
|
614
|
+
const globalOffset = {
|
|
615
|
+
x: -(bounds.right + bounds.left) / 2,
|
|
616
|
+
y: -(bounds.top + bounds.bottom) / 2
|
|
617
|
+
};
|
|
618
|
+
for (const { component, selector } of involvedComponents) {
|
|
619
|
+
const kvx = getKVar(`${selector}_x`);
|
|
620
|
+
const kvy = getKVar(`${selector}_y`);
|
|
621
|
+
component._setPositionFromLayout({
|
|
622
|
+
x: kvx.value() + globalOffset.x,
|
|
623
|
+
y: kvy.value() + globalOffset.y
|
|
624
|
+
});
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
}
|
|
469
628
|
};
|
|
470
629
|
|
|
471
630
|
// lib/components/base-components/NormalComponent.ts
|
|
@@ -507,16 +666,16 @@ var Port = class extends PrimitiveComponent {
|
|
|
507
666
|
super(props);
|
|
508
667
|
this.matchedComponents = [];
|
|
509
668
|
}
|
|
510
|
-
|
|
669
|
+
_getGlobalPcbPositionBeforeLayout() {
|
|
511
670
|
const matchedPcbElm = this.matchedComponents.find((c) => c.isPcbPrimitive);
|
|
512
671
|
if (!matchedPcbElm) {
|
|
513
672
|
throw new Error(
|
|
514
673
|
`Port ${this} has no matched pcb component, can't get global schematic position`
|
|
515
674
|
);
|
|
516
675
|
}
|
|
517
|
-
return matchedPcbElm?.
|
|
676
|
+
return matchedPcbElm?._getGlobalPcbPositionBeforeLayout() ?? { x: 0, y: 0 };
|
|
518
677
|
}
|
|
519
|
-
|
|
678
|
+
_getGlobalSchematicPositionBeforeLayout() {
|
|
520
679
|
if (!this.schematicSymbolPortDef) {
|
|
521
680
|
return applyToPoint2(this.parent.computeSchematicGlobalTransform(), {
|
|
522
681
|
x: 0,
|
|
@@ -600,11 +759,6 @@ var Port = class extends PrimitiveComponent {
|
|
|
600
759
|
});
|
|
601
760
|
this.source_component_id = this.parent?.source_component_id;
|
|
602
761
|
}
|
|
603
|
-
/**
|
|
604
|
-
* For PcbPorts, we use the parent attachment phase to determine where to place
|
|
605
|
-
* the pcb_port (prior to this phase, the smtpad/platedhole isn't guaranteed
|
|
606
|
-
* to exist)
|
|
607
|
-
*/
|
|
608
762
|
doInitialPcbPortRender() {
|
|
609
763
|
const { db } = this.root;
|
|
610
764
|
const { matchedComponents } = this;
|
|
@@ -621,17 +775,17 @@ var Port = class extends PrimitiveComponent {
|
|
|
621
775
|
);
|
|
622
776
|
}
|
|
623
777
|
const pcbMatch = pcbMatches[0];
|
|
624
|
-
if ("
|
|
778
|
+
if ("_getCircuitJsonBounds" in pcbMatch) {
|
|
625
779
|
const pcb_port = db.pcb_port.insert({
|
|
626
780
|
pcb_component_id: this.parent?.pcb_component_id,
|
|
627
781
|
layers: ["top"],
|
|
628
|
-
...pcbMatch.
|
|
782
|
+
...pcbMatch._getCircuitJsonBounds().center,
|
|
629
783
|
source_port_id: this.source_port_id
|
|
630
784
|
});
|
|
631
785
|
this.pcb_port_id = pcb_port.pcb_port_id;
|
|
632
786
|
} else {
|
|
633
787
|
throw new Error(
|
|
634
|
-
`${pcbMatch.getString()} does not have a
|
|
788
|
+
`${pcbMatch.getString()} does not have a _getGlobalPcbPositionBeforeLayout method (needed for pcb_port placement)`
|
|
635
789
|
);
|
|
636
790
|
}
|
|
637
791
|
}
|
|
@@ -639,8 +793,8 @@ var Port = class extends PrimitiveComponent {
|
|
|
639
793
|
const { db } = this.root;
|
|
640
794
|
const { _parsedProps: props } = this;
|
|
641
795
|
if (!this.parent) return;
|
|
642
|
-
const center = this.
|
|
643
|
-
const parentCenter = this.parent?.
|
|
796
|
+
const center = this._getGlobalSchematicPositionBeforeLayout();
|
|
797
|
+
const parentCenter = this.parent?._getGlobalSchematicPositionBeforeLayout();
|
|
644
798
|
this.facingDirection = getRelativeDirection(parentCenter, center);
|
|
645
799
|
const schematic_port = db.schematic_port.insert({
|
|
646
800
|
schematic_component_id: this.parent?.schematic_component_id,
|
|
@@ -852,8 +1006,8 @@ var SmtPad = class extends PrimitiveComponent {
|
|
|
852
1006
|
);
|
|
853
1007
|
}
|
|
854
1008
|
doInitialPortMatching() {
|
|
855
|
-
const parentPorts =
|
|
856
|
-
|
|
1009
|
+
const parentPorts = this.getPrimitiveContainer()?.selectAll(
|
|
1010
|
+
"port"
|
|
857
1011
|
);
|
|
858
1012
|
if (!this.props.portHints) {
|
|
859
1013
|
return;
|
|
@@ -870,8 +1024,10 @@ var SmtPad = class extends PrimitiveComponent {
|
|
|
870
1024
|
const { db } = this.root;
|
|
871
1025
|
const { _parsedProps: props } = this;
|
|
872
1026
|
if (!props.portHints) return;
|
|
873
|
-
const position = this.
|
|
874
|
-
const decomposedMat = decomposeTSR(
|
|
1027
|
+
const position = this._getGlobalPcbPositionBeforeLayout();
|
|
1028
|
+
const decomposedMat = decomposeTSR(
|
|
1029
|
+
this._computePcbGlobalTransformBeforeLayout()
|
|
1030
|
+
);
|
|
875
1031
|
const isRotated90 = Math.abs(decomposedMat.rotation.angle * (180 / Math.PI) - 90) < 0.01;
|
|
876
1032
|
let pcb_smtpad = null;
|
|
877
1033
|
if (props.shape === "circle") {
|
|
@@ -902,6 +1058,46 @@ var SmtPad = class extends PrimitiveComponent {
|
|
|
902
1058
|
this.pcb_smtpad_id = pcb_smtpad.pcb_smtpad_id;
|
|
903
1059
|
}
|
|
904
1060
|
}
|
|
1061
|
+
_getCircuitJsonBounds() {
|
|
1062
|
+
const { db } = this.root;
|
|
1063
|
+
const smtpad = db.pcb_smtpad.get(this.pcb_smtpad_id);
|
|
1064
|
+
if (smtpad.shape === "rect") {
|
|
1065
|
+
return {
|
|
1066
|
+
center: { x: smtpad.x, y: smtpad.y },
|
|
1067
|
+
bounds: {
|
|
1068
|
+
left: smtpad.x - smtpad.width / 2,
|
|
1069
|
+
top: smtpad.y - smtpad.height / 2,
|
|
1070
|
+
right: smtpad.x + smtpad.width / 2,
|
|
1071
|
+
bottom: smtpad.y + smtpad.height / 2
|
|
1072
|
+
},
|
|
1073
|
+
width: smtpad.width,
|
|
1074
|
+
height: smtpad.height
|
|
1075
|
+
};
|
|
1076
|
+
}
|
|
1077
|
+
if (smtpad.shape === "circle") {
|
|
1078
|
+
return {
|
|
1079
|
+
center: { x: smtpad.x, y: smtpad.y },
|
|
1080
|
+
bounds: {
|
|
1081
|
+
left: smtpad.x - smtpad.radius,
|
|
1082
|
+
top: smtpad.y - smtpad.radius,
|
|
1083
|
+
right: smtpad.x + smtpad.radius,
|
|
1084
|
+
bottom: smtpad.y + smtpad.radius
|
|
1085
|
+
},
|
|
1086
|
+
width: smtpad.radius * 2,
|
|
1087
|
+
height: smtpad.radius * 2
|
|
1088
|
+
};
|
|
1089
|
+
}
|
|
1090
|
+
throw new Error(
|
|
1091
|
+
`circuitJson bounds calculation not implemented for shape "${smtpad.shape}"`
|
|
1092
|
+
);
|
|
1093
|
+
}
|
|
1094
|
+
_setPositionFromLayout(newCenter) {
|
|
1095
|
+
const { db } = this.root;
|
|
1096
|
+
db.pcb_smtpad.update(this.pcb_smtpad_id, {
|
|
1097
|
+
x: newCenter.x,
|
|
1098
|
+
y: newCenter.y
|
|
1099
|
+
});
|
|
1100
|
+
}
|
|
905
1101
|
};
|
|
906
1102
|
|
|
907
1103
|
// lib/components/primitive-components/SilkscreenPath.ts
|
|
@@ -923,7 +1119,7 @@ var SilkscreenPath = class extends PrimitiveComponent {
|
|
|
923
1119
|
`Invalid layer "${layer}" for SilkscreenPath. Must be "top" or "bottom".`
|
|
924
1120
|
);
|
|
925
1121
|
}
|
|
926
|
-
const transform = this.
|
|
1122
|
+
const transform = this._computePcbGlobalTransformBeforeLayout();
|
|
927
1123
|
const pcb_silkscreen_path = db.pcb_silkscreen_path.insert({
|
|
928
1124
|
pcb_component_id: this.parent?.pcb_component_id,
|
|
929
1125
|
layer,
|
|
@@ -986,7 +1182,7 @@ var PlatedHole = class extends PrimitiveComponent {
|
|
|
986
1182
|
const { db } = this.root;
|
|
987
1183
|
const { _parsedProps: props } = this;
|
|
988
1184
|
if (!props.portHints) return;
|
|
989
|
-
const position = this.
|
|
1185
|
+
const position = this._getGlobalPcbPositionBeforeLayout();
|
|
990
1186
|
if (props.shape === "circle") {
|
|
991
1187
|
const plated_hole_input = {
|
|
992
1188
|
pcb_component_id: this.parent?.pcb_component_id,
|
|
@@ -1154,10 +1350,10 @@ var Net = class extends PrimitiveComponent {
|
|
|
1154
1350
|
const islandPairs = pairs(islands);
|
|
1155
1351
|
for (const [A, B] of islandPairs) {
|
|
1156
1352
|
const Apositions = A.ports.map(
|
|
1157
|
-
(port) => port.
|
|
1353
|
+
(port) => port._getGlobalPcbPositionBeforeLayout()
|
|
1158
1354
|
);
|
|
1159
1355
|
const Bpositions = B.ports.map(
|
|
1160
|
-
(port) => port.
|
|
1356
|
+
(port) => port._getGlobalPcbPositionBeforeLayout()
|
|
1161
1357
|
);
|
|
1162
1358
|
let closestDist = Infinity;
|
|
1163
1359
|
let closestPair = [-1, -1];
|
|
@@ -1215,6 +1411,7 @@ var createNetsFromProps = (component, props) => {
|
|
|
1215
1411
|
// lib/components/base-components/NormalComponent.ts
|
|
1216
1412
|
var NormalComponent = class extends PrimitiveComponent {
|
|
1217
1413
|
reactSubtrees = [];
|
|
1414
|
+
isPrimitiveContainer = true;
|
|
1218
1415
|
constructor(props) {
|
|
1219
1416
|
super(props);
|
|
1220
1417
|
this._addChildrenFromStringFootprint();
|
|
@@ -1345,7 +1542,7 @@ var NormalComponent = class extends PrimitiveComponent {
|
|
|
1345
1542
|
const { db } = this.root;
|
|
1346
1543
|
const { _parsedProps: props } = this;
|
|
1347
1544
|
const pcb_component = db.pcb_component.insert({
|
|
1348
|
-
center: this.
|
|
1545
|
+
center: this._getGlobalPcbPositionBeforeLayout(),
|
|
1349
1546
|
// width/height are computed in the PcbComponentSizeCalculation phase
|
|
1350
1547
|
width: 0,
|
|
1351
1548
|
height: 0,
|
|
@@ -1369,7 +1566,7 @@ var NormalComponent = class extends PrimitiveComponent {
|
|
|
1369
1566
|
let maxY = -Infinity;
|
|
1370
1567
|
for (const child of this.children) {
|
|
1371
1568
|
if (child.isPcbPrimitive) {
|
|
1372
|
-
const { x, y } = child.
|
|
1569
|
+
const { x, y } = child._getGlobalPcbPositionBeforeLayout();
|
|
1373
1570
|
const { width: width2, height: height2 } = child.getPcbSize();
|
|
1374
1571
|
minX = Math.min(minX, x - width2 / 2);
|
|
1375
1572
|
minY = Math.min(minY, y - height2 / 2);
|
|
@@ -1577,7 +1774,7 @@ var Board = class extends Group {
|
|
|
1577
1774
|
db.pcb_board.delete(this.pcb_board_id);
|
|
1578
1775
|
this.pcb_board_id = null;
|
|
1579
1776
|
}
|
|
1580
|
-
|
|
1777
|
+
_computePcbGlobalTransformBeforeLayout() {
|
|
1581
1778
|
return identity4();
|
|
1582
1779
|
}
|
|
1583
1780
|
};
|
|
@@ -1718,8 +1915,8 @@ var mergeRoutes = (routes) => {
|
|
|
1718
1915
|
|
|
1719
1916
|
// lib/utils/getClosest.ts
|
|
1720
1917
|
var getDistance = (a, b) => {
|
|
1721
|
-
const aPos = "
|
|
1722
|
-
const bPos = "
|
|
1918
|
+
const aPos = "_getGlobalPcbPositionBeforeLayout" in a ? a._getGlobalPcbPositionBeforeLayout() : a;
|
|
1919
|
+
const bPos = "_getGlobalPcbPositionBeforeLayout" in b ? b._getGlobalPcbPositionBeforeLayout() : b;
|
|
1723
1920
|
return Math.sqrt((aPos.x - bPos.x) ** 2 + (aPos.y - bPos.y) ** 2);
|
|
1724
1921
|
};
|
|
1725
1922
|
function getClosest(point, candidates) {
|
|
@@ -1740,7 +1937,7 @@ function getClosest(point, candidates) {
|
|
|
1740
1937
|
// lib/components/primitive-components/Trace.ts
|
|
1741
1938
|
import "zod";
|
|
1742
1939
|
var portToObjective = (port) => {
|
|
1743
|
-
const portPosition = port.
|
|
1940
|
+
const portPosition = port._getGlobalPcbPositionBeforeLayout();
|
|
1744
1941
|
return {
|
|
1745
1942
|
...portPosition,
|
|
1746
1943
|
layers: port.getAvailablePcbLayers()
|
|
@@ -2056,7 +2253,7 @@ searched component ${targetComponent.getString()}, which has ports: ${targetComp
|
|
|
2056
2253
|
for (const { port } of ports) {
|
|
2057
2254
|
connection.pointsToConnect.push(
|
|
2058
2255
|
projectPointInDirection(
|
|
2059
|
-
port.
|
|
2256
|
+
port._getGlobalSchematicPositionBeforeLayout(),
|
|
2060
2257
|
port.facingDirection,
|
|
2061
2258
|
0.1501
|
|
2062
2259
|
)
|
|
@@ -2251,7 +2448,7 @@ var TraceHint = class extends PrimitiveComponent {
|
|
|
2251
2448
|
const { _parsedProps: props } = this;
|
|
2252
2449
|
const offsets = props.offset ? [props.offset] : props.offsets;
|
|
2253
2450
|
if (!offsets) return [];
|
|
2254
|
-
const globalTransform = this.
|
|
2451
|
+
const globalTransform = this._computePcbGlobalTransformBeforeLayout();
|
|
2255
2452
|
return offsets.map(
|
|
2256
2453
|
(offset) => ({
|
|
2257
2454
|
...applyToPoint4(globalTransform, offset),
|
|
@@ -2687,6 +2884,43 @@ var Jumper = class extends NormalComponent {
|
|
|
2687
2884
|
}
|
|
2688
2885
|
};
|
|
2689
2886
|
|
|
2887
|
+
// lib/components/primitive-components/Constraint.ts
|
|
2888
|
+
import { constraintProps } from "@tscircuit/props";
|
|
2889
|
+
import "zod";
|
|
2890
|
+
var Constraint2 = class extends PrimitiveComponent {
|
|
2891
|
+
get config() {
|
|
2892
|
+
return {
|
|
2893
|
+
zodProps: constraintProps
|
|
2894
|
+
};
|
|
2895
|
+
}
|
|
2896
|
+
constructor(props) {
|
|
2897
|
+
super(props);
|
|
2898
|
+
if ("xdist" in props || "ydist" in props) {
|
|
2899
|
+
if (!("edgeToEdge" in props) && !("centerToCenter" in props)) {
|
|
2900
|
+
throw new Error(
|
|
2901
|
+
"edgeToEdge, centerToCenter (or from*/to* props) must be set for xdist or ydist for <constraint />"
|
|
2902
|
+
);
|
|
2903
|
+
}
|
|
2904
|
+
}
|
|
2905
|
+
}
|
|
2906
|
+
_getAllReferencedComponents() {
|
|
2907
|
+
const componentsWithSelectors = [];
|
|
2908
|
+
for (const key of ["left", "right", "top", "bottom"]) {
|
|
2909
|
+
if (key in this._parsedProps) {
|
|
2910
|
+
const selector = this._parsedProps[key];
|
|
2911
|
+
const component = this.getSubcircuit().selectOne(selector);
|
|
2912
|
+
if (component) {
|
|
2913
|
+
componentsWithSelectors.push({
|
|
2914
|
+
selector,
|
|
2915
|
+
component
|
|
2916
|
+
});
|
|
2917
|
+
}
|
|
2918
|
+
}
|
|
2919
|
+
}
|
|
2920
|
+
return { componentsWithSelectors };
|
|
2921
|
+
}
|
|
2922
|
+
};
|
|
2923
|
+
|
|
2690
2924
|
// lib/Project.ts
|
|
2691
2925
|
import { su } from "@tscircuit/soup-util";
|
|
2692
2926
|
import { isValidElement as isValidElement2 } from "react";
|
|
@@ -2768,7 +3002,7 @@ var Circuit = class {
|
|
|
2768
3002
|
computeSchematicGlobalTransform() {
|
|
2769
3003
|
return identity5();
|
|
2770
3004
|
}
|
|
2771
|
-
|
|
3005
|
+
_computePcbGlobalTransformBeforeLayout() {
|
|
2772
3006
|
return identity5();
|
|
2773
3007
|
}
|
|
2774
3008
|
selectAll(selector) {
|
|
@@ -2790,6 +3024,7 @@ export {
|
|
|
2790
3024
|
Capacitor,
|
|
2791
3025
|
Chip,
|
|
2792
3026
|
Circuit,
|
|
3027
|
+
Constraint2 as Constraint,
|
|
2793
3028
|
Footprint,
|
|
2794
3029
|
Group,
|
|
2795
3030
|
Jumper,
|
package/lib/Project.ts
CHANGED
|
@@ -108,7 +108,7 @@ export class Circuit {
|
|
|
108
108
|
return identity()
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
-
|
|
111
|
+
_computePcbGlobalTransformBeforeLayout(): Matrix {
|
|
112
112
|
return identity()
|
|
113
113
|
}
|
|
114
114
|
|
|
@@ -124,4 +124,7 @@ export class Circuit {
|
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
+
/**
|
|
128
|
+
* @deprecated
|
|
129
|
+
*/
|
|
127
130
|
export const Project = Circuit
|
|
@@ -46,6 +46,8 @@ export class NormalComponent<
|
|
|
46
46
|
> extends PrimitiveComponent<ZodProps> {
|
|
47
47
|
reactSubtrees: Array<ReactSubtree> = []
|
|
48
48
|
|
|
49
|
+
isPrimitiveContainer = true
|
|
50
|
+
|
|
49
51
|
constructor(props: z.input<ZodProps>) {
|
|
50
52
|
super(props)
|
|
51
53
|
this._addChildrenFromStringFootprint()
|
|
@@ -199,7 +201,7 @@ export class NormalComponent<
|
|
|
199
201
|
const { db } = this.root!
|
|
200
202
|
const { _parsedProps: props } = this
|
|
201
203
|
const pcb_component = db.pcb_component.insert({
|
|
202
|
-
center: this.
|
|
204
|
+
center: this._getGlobalPcbPositionBeforeLayout(),
|
|
203
205
|
// width/height are computed in the PcbComponentSizeCalculation phase
|
|
204
206
|
width: 0,
|
|
205
207
|
height: 0,
|
|
@@ -226,7 +228,7 @@ export class NormalComponent<
|
|
|
226
228
|
|
|
227
229
|
for (const child of this.children) {
|
|
228
230
|
if (child.isPcbPrimitive) {
|
|
229
|
-
const { x, y } = child.
|
|
231
|
+
const { x, y } = child._getGlobalPcbPositionBeforeLayout()
|
|
230
232
|
const { width, height } = child.getPcbSize()
|
|
231
233
|
minX = Math.min(minX, x - width / 2)
|
|
232
234
|
minY = Math.min(minY, y - height / 2)
|