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