@tscircuit/core 0.0.29 → 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 +208 -56
- package/dist/index.js +368 -97
- package/lib/Project.ts +19 -15
- package/lib/components/base-components/NormalComponent.ts +61 -13
- package/lib/components/base-components/PrimitiveComponent.ts +63 -19
- package/lib/components/base-components/Renderable.ts +5 -3
- package/lib/components/index.ts +1 -0
- package/lib/components/normal-components/Board.ts +3 -3
- package/lib/components/normal-components/Capacitor.ts +1 -1
- package/lib/components/normal-components/Chip.ts +3 -3
- package/lib/components/normal-components/Jumper.ts +3 -3
- package/lib/components/normal-components/Resistor.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 +4 -4
- package/lib/components/primitive-components/PlatedHole.ts +2 -2
- package/lib/components/primitive-components/Port.ts +12 -17
- package/lib/components/primitive-components/SilkscreenPath.ts +2 -2
- package/lib/components/primitive-components/SmtPad.ts +55 -5
- package/lib/components/primitive-components/Trace.ts +7 -7
- package/lib/components/primitive-components/TraceHint.ts +2 -2
- 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,13 +37,12 @@ import "react";
|
|
|
36
37
|
import "react";
|
|
37
38
|
var orderedRenderPhases = [
|
|
38
39
|
"ReactSubtreesRender",
|
|
39
|
-
|
|
40
|
+
"InitializePortsFromChildren",
|
|
40
41
|
"CreateNetsFromProps",
|
|
41
42
|
"CreateTracesFromProps",
|
|
42
43
|
"SourceRender",
|
|
43
44
|
"SourceParentAttachment",
|
|
44
45
|
"PortDiscovery",
|
|
45
|
-
// probably going to be removed b/c port discovery can always be done on prop change
|
|
46
46
|
"PortMatching",
|
|
47
47
|
"SourceTraceRender",
|
|
48
48
|
"SchematicComponentRender",
|
|
@@ -50,8 +50,9 @@ var orderedRenderPhases = [
|
|
|
50
50
|
"SchematicPortRender",
|
|
51
51
|
"SchematicTraceRender",
|
|
52
52
|
"PcbComponentRender",
|
|
53
|
-
"PcbPortRender",
|
|
54
53
|
"PcbPrimitiveRender",
|
|
54
|
+
"PcbFootprintLayout",
|
|
55
|
+
"PcbPortRender",
|
|
55
56
|
"PcbParentAttachment",
|
|
56
57
|
"PcbLayout",
|
|
57
58
|
"PcbTraceRender",
|
|
@@ -169,7 +170,6 @@ var PrimitiveComponent = class extends Renderable {
|
|
|
169
170
|
zodProps: z.object({}).passthrough()
|
|
170
171
|
};
|
|
171
172
|
}
|
|
172
|
-
project = null;
|
|
173
173
|
props;
|
|
174
174
|
_parsedProps;
|
|
175
175
|
componentName = "";
|
|
@@ -183,8 +183,19 @@ var PrimitiveComponent = class extends Renderable {
|
|
|
183
183
|
*/
|
|
184
184
|
get isSubcircuit() {
|
|
185
185
|
return Boolean(this.props.subcircuit) || // Implied opaque group for top-level group
|
|
186
|
-
this.lowercaseComponentName === "group" && this?.parent?.
|
|
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;
|
|
@@ -204,12 +215,6 @@ var PrimitiveComponent = class extends Renderable {
|
|
|
204
215
|
this.lowercaseComponentName = this.componentName.toLowerCase();
|
|
205
216
|
}
|
|
206
217
|
}
|
|
207
|
-
setProject(project) {
|
|
208
|
-
this.project = project;
|
|
209
|
-
for (const c of this.children) {
|
|
210
|
-
c.setProject(project);
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
218
|
setProps(props) {
|
|
214
219
|
const newProps = this.config.zodProps.parse({
|
|
215
220
|
...this.props,
|
|
@@ -242,14 +247,14 @@ var PrimitiveComponent = class extends Renderable {
|
|
|
242
247
|
* components, including this component's translation and rotation.
|
|
243
248
|
*
|
|
244
249
|
* This is used to compute this component's position as well as all children
|
|
245
|
-
* components positions
|
|
250
|
+
* components positions before layout is applied
|
|
246
251
|
*/
|
|
247
|
-
|
|
252
|
+
_computePcbGlobalTransformBeforeLayout() {
|
|
248
253
|
const { _parsedProps: props } = this;
|
|
249
254
|
const manualPlacement = this.getSubcircuit()._getManualPlacementForComponent(this);
|
|
250
255
|
if (manualPlacement && this.props.pcbX === void 0 && this.props.pcbY === void 0) {
|
|
251
256
|
return compose(
|
|
252
|
-
this.parent?.
|
|
257
|
+
this.parent?._computePcbGlobalTransformBeforeLayout() ?? identity(),
|
|
253
258
|
compose(
|
|
254
259
|
translate(manualPlacement.x, manualPlacement.y),
|
|
255
260
|
rotate((props.pcbRotation ?? 0) * Math.PI / 180)
|
|
@@ -257,10 +262,37 @@ var PrimitiveComponent = class extends Renderable {
|
|
|
257
262
|
);
|
|
258
263
|
}
|
|
259
264
|
return compose(
|
|
260
|
-
this.parent?.
|
|
265
|
+
this.parent?._computePcbGlobalTransformBeforeLayout() ?? identity(),
|
|
261
266
|
this.computePcbPropsTransform()
|
|
262
267
|
);
|
|
263
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
|
+
}
|
|
264
296
|
/**
|
|
265
297
|
* Computes a transformation matrix from the props of this component for
|
|
266
298
|
* schematic components
|
|
@@ -301,7 +333,7 @@ var PrimitiveComponent = class extends Renderable {
|
|
|
301
333
|
for (const position of placementConfig.positions) {
|
|
302
334
|
if (isMatchingSelector(component, position.selector)) {
|
|
303
335
|
const center = applyToPoint(
|
|
304
|
-
this.
|
|
336
|
+
this._computePcbGlobalTransformBeforeLayout(),
|
|
305
337
|
position.center
|
|
306
338
|
);
|
|
307
339
|
return center;
|
|
@@ -309,15 +341,20 @@ var PrimitiveComponent = class extends Renderable {
|
|
|
309
341
|
}
|
|
310
342
|
return null;
|
|
311
343
|
}
|
|
312
|
-
|
|
313
|
-
return applyToPoint(this.
|
|
344
|
+
_getGlobalPcbPositionBeforeLayout() {
|
|
345
|
+
return applyToPoint(this._computePcbGlobalTransformBeforeLayout(), {
|
|
346
|
+
x: 0,
|
|
347
|
+
y: 0
|
|
348
|
+
});
|
|
314
349
|
}
|
|
315
|
-
|
|
350
|
+
_getGlobalSchematicPositionBeforeLayout() {
|
|
316
351
|
return applyToPoint(this.computeSchematicGlobalTransform(), { x: 0, y: 0 });
|
|
317
352
|
}
|
|
353
|
+
get root() {
|
|
354
|
+
return this.parent?.root ?? null;
|
|
355
|
+
}
|
|
318
356
|
onAddToParent(parent) {
|
|
319
357
|
this.parent = parent;
|
|
320
|
-
this.project = parent.project;
|
|
321
358
|
}
|
|
322
359
|
/**
|
|
323
360
|
* Called whenever the props change
|
|
@@ -469,7 +506,125 @@ var PrimitiveComponent = class extends Renderable {
|
|
|
469
506
|
};
|
|
470
507
|
|
|
471
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");
|
|
472
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
|
+
}
|
|
473
628
|
};
|
|
474
629
|
|
|
475
630
|
// lib/components/base-components/NormalComponent.ts
|
|
@@ -511,16 +666,16 @@ var Port = class extends PrimitiveComponent {
|
|
|
511
666
|
super(props);
|
|
512
667
|
this.matchedComponents = [];
|
|
513
668
|
}
|
|
514
|
-
|
|
669
|
+
_getGlobalPcbPositionBeforeLayout() {
|
|
515
670
|
const matchedPcbElm = this.matchedComponents.find((c) => c.isPcbPrimitive);
|
|
516
671
|
if (!matchedPcbElm) {
|
|
517
672
|
throw new Error(
|
|
518
673
|
`Port ${this} has no matched pcb component, can't get global schematic position`
|
|
519
674
|
);
|
|
520
675
|
}
|
|
521
|
-
return matchedPcbElm?.
|
|
676
|
+
return matchedPcbElm?._getGlobalPcbPositionBeforeLayout() ?? { x: 0, y: 0 };
|
|
522
677
|
}
|
|
523
|
-
|
|
678
|
+
_getGlobalSchematicPositionBeforeLayout() {
|
|
524
679
|
if (!this.schematicSymbolPortDef) {
|
|
525
680
|
return applyToPoint2(this.parent.computeSchematicGlobalTransform(), {
|
|
526
681
|
x: 0,
|
|
@@ -581,7 +736,7 @@ var Port = class extends PrimitiveComponent {
|
|
|
581
736
|
return connectedTraces;
|
|
582
737
|
}
|
|
583
738
|
doInitialSourceRender() {
|
|
584
|
-
const { db } = this.
|
|
739
|
+
const { db } = this.root;
|
|
585
740
|
const { _parsedProps: props } = this;
|
|
586
741
|
const port_hints = this.getNameAndAliases();
|
|
587
742
|
const source_port = db.source_port.insert({
|
|
@@ -593,7 +748,7 @@ var Port = class extends PrimitiveComponent {
|
|
|
593
748
|
this.source_port_id = source_port.source_port_id;
|
|
594
749
|
}
|
|
595
750
|
doInitialSourceParentAttachment() {
|
|
596
|
-
const { db } = this.
|
|
751
|
+
const { db } = this.root;
|
|
597
752
|
if (!this.parent?.source_component_id) {
|
|
598
753
|
throw new Error(
|
|
599
754
|
`${this.getString()} has no parent source component (parent: ${this.parent?.getString()})`
|
|
@@ -604,13 +759,8 @@ var Port = class extends PrimitiveComponent {
|
|
|
604
759
|
});
|
|
605
760
|
this.source_component_id = this.parent?.source_component_id;
|
|
606
761
|
}
|
|
607
|
-
/**
|
|
608
|
-
* For PcbPorts, we use the parent attachment phase to determine where to place
|
|
609
|
-
* the pcb_port (prior to this phase, the smtpad/platedhole isn't guaranteed
|
|
610
|
-
* to exist)
|
|
611
|
-
*/
|
|
612
762
|
doInitialPcbPortRender() {
|
|
613
|
-
const { db } = this.
|
|
763
|
+
const { db } = this.root;
|
|
614
764
|
const { matchedComponents } = this;
|
|
615
765
|
if (!this.parent?.pcb_component_id) {
|
|
616
766
|
throw new Error(
|
|
@@ -625,26 +775,26 @@ var Port = class extends PrimitiveComponent {
|
|
|
625
775
|
);
|
|
626
776
|
}
|
|
627
777
|
const pcbMatch = pcbMatches[0];
|
|
628
|
-
if ("
|
|
778
|
+
if ("_getCircuitJsonBounds" in pcbMatch) {
|
|
629
779
|
const pcb_port = db.pcb_port.insert({
|
|
630
780
|
pcb_component_id: this.parent?.pcb_component_id,
|
|
631
781
|
layers: ["top"],
|
|
632
|
-
...pcbMatch.
|
|
782
|
+
...pcbMatch._getCircuitJsonBounds().center,
|
|
633
783
|
source_port_id: this.source_port_id
|
|
634
784
|
});
|
|
635
785
|
this.pcb_port_id = pcb_port.pcb_port_id;
|
|
636
786
|
} else {
|
|
637
787
|
throw new Error(
|
|
638
|
-
`${pcbMatch.getString()} does not have a
|
|
788
|
+
`${pcbMatch.getString()} does not have a _getGlobalPcbPositionBeforeLayout method (needed for pcb_port placement)`
|
|
639
789
|
);
|
|
640
790
|
}
|
|
641
791
|
}
|
|
642
792
|
doInitialSchematicPortRender() {
|
|
643
|
-
const { db } = this.
|
|
793
|
+
const { db } = this.root;
|
|
644
794
|
const { _parsedProps: props } = this;
|
|
645
795
|
if (!this.parent) return;
|
|
646
|
-
const center = this.
|
|
647
|
-
const parentCenter = this.parent?.
|
|
796
|
+
const center = this._getGlobalSchematicPositionBeforeLayout();
|
|
797
|
+
const parentCenter = this.parent?._getGlobalSchematicPositionBeforeLayout();
|
|
648
798
|
this.facingDirection = getRelativeDirection(parentCenter, center);
|
|
649
799
|
const schematic_port = db.schematic_port.insert({
|
|
650
800
|
schematic_component_id: this.parent?.schematic_component_id,
|
|
@@ -856,8 +1006,8 @@ var SmtPad = class extends PrimitiveComponent {
|
|
|
856
1006
|
);
|
|
857
1007
|
}
|
|
858
1008
|
doInitialPortMatching() {
|
|
859
|
-
const parentPorts =
|
|
860
|
-
|
|
1009
|
+
const parentPorts = this.getPrimitiveContainer()?.selectAll(
|
|
1010
|
+
"port"
|
|
861
1011
|
);
|
|
862
1012
|
if (!this.props.portHints) {
|
|
863
1013
|
return;
|
|
@@ -871,11 +1021,13 @@ var SmtPad = class extends PrimitiveComponent {
|
|
|
871
1021
|
}
|
|
872
1022
|
}
|
|
873
1023
|
doInitialPcbPrimitiveRender() {
|
|
874
|
-
const { db } = this.
|
|
1024
|
+
const { db } = this.root;
|
|
875
1025
|
const { _parsedProps: props } = this;
|
|
876
1026
|
if (!props.portHints) return;
|
|
877
|
-
const position = this.
|
|
878
|
-
const decomposedMat = decomposeTSR(
|
|
1027
|
+
const position = this._getGlobalPcbPositionBeforeLayout();
|
|
1028
|
+
const decomposedMat = decomposeTSR(
|
|
1029
|
+
this._computePcbGlobalTransformBeforeLayout()
|
|
1030
|
+
);
|
|
879
1031
|
const isRotated90 = Math.abs(decomposedMat.rotation.angle * (180 / Math.PI) - 90) < 0.01;
|
|
880
1032
|
let pcb_smtpad = null;
|
|
881
1033
|
if (props.shape === "circle") {
|
|
@@ -906,6 +1058,46 @@ var SmtPad = class extends PrimitiveComponent {
|
|
|
906
1058
|
this.pcb_smtpad_id = pcb_smtpad.pcb_smtpad_id;
|
|
907
1059
|
}
|
|
908
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
|
+
}
|
|
909
1101
|
};
|
|
910
1102
|
|
|
911
1103
|
// lib/components/primitive-components/SilkscreenPath.ts
|
|
@@ -919,7 +1111,7 @@ var SilkscreenPath = class extends PrimitiveComponent {
|
|
|
919
1111
|
};
|
|
920
1112
|
}
|
|
921
1113
|
doInitialPcbPrimitiveRender() {
|
|
922
|
-
const { db } = this.
|
|
1114
|
+
const { db } = this.root;
|
|
923
1115
|
const { _parsedProps: props } = this;
|
|
924
1116
|
const layer = props.layer ?? "top";
|
|
925
1117
|
if (layer !== "top" && layer !== "bottom") {
|
|
@@ -927,7 +1119,7 @@ var SilkscreenPath = class extends PrimitiveComponent {
|
|
|
927
1119
|
`Invalid layer "${layer}" for SilkscreenPath. Must be "top" or "bottom".`
|
|
928
1120
|
);
|
|
929
1121
|
}
|
|
930
|
-
const transform = this.
|
|
1122
|
+
const transform = this._computePcbGlobalTransformBeforeLayout();
|
|
931
1123
|
const pcb_silkscreen_path = db.pcb_silkscreen_path.insert({
|
|
932
1124
|
pcb_component_id: this.parent?.pcb_component_id,
|
|
933
1125
|
layer,
|
|
@@ -987,10 +1179,10 @@ var PlatedHole = class extends PrimitiveComponent {
|
|
|
987
1179
|
}
|
|
988
1180
|
}
|
|
989
1181
|
doInitialPcbPrimitiveRender() {
|
|
990
|
-
const { db } = this.
|
|
1182
|
+
const { db } = this.root;
|
|
991
1183
|
const { _parsedProps: props } = this;
|
|
992
1184
|
if (!props.portHints) return;
|
|
993
|
-
const position = this.
|
|
1185
|
+
const position = this._getGlobalPcbPositionBeforeLayout();
|
|
994
1186
|
if (props.shape === "circle") {
|
|
995
1187
|
const plated_hole_input = {
|
|
996
1188
|
pcb_component_id: this.parent?.pcb_component_id,
|
|
@@ -1085,7 +1277,7 @@ var Net = class extends PrimitiveComponent {
|
|
|
1085
1277
|
return `net.${this.props.name}`;
|
|
1086
1278
|
}
|
|
1087
1279
|
doInitialSourceComponentRender() {
|
|
1088
|
-
const { db } = this.
|
|
1280
|
+
const { db } = this.root;
|
|
1089
1281
|
const { _parsedProps: props } = this;
|
|
1090
1282
|
const net = db.source_net.insert({
|
|
1091
1283
|
name: props.name,
|
|
@@ -1134,7 +1326,7 @@ var Net = class extends PrimitiveComponent {
|
|
|
1134
1326
|
* such that the nets are fully connected
|
|
1135
1327
|
*/
|
|
1136
1328
|
doInitialPcbRouteNetIslands() {
|
|
1137
|
-
const { db } = this.
|
|
1329
|
+
const { db } = this.root;
|
|
1138
1330
|
const { _parsedProps: props } = this;
|
|
1139
1331
|
const traces = this._getAllDirectlyConnectedTraces().filter(
|
|
1140
1332
|
(trace) => (trace._portsRoutedOnPcb?.length ?? 0) > 0
|
|
@@ -1158,10 +1350,10 @@ var Net = class extends PrimitiveComponent {
|
|
|
1158
1350
|
const islandPairs = pairs(islands);
|
|
1159
1351
|
for (const [A, B] of islandPairs) {
|
|
1160
1352
|
const Apositions = A.ports.map(
|
|
1161
|
-
(port) => port.
|
|
1353
|
+
(port) => port._getGlobalPcbPositionBeforeLayout()
|
|
1162
1354
|
);
|
|
1163
1355
|
const Bpositions = B.ports.map(
|
|
1164
|
-
(port) => port.
|
|
1356
|
+
(port) => port._getGlobalPcbPositionBeforeLayout()
|
|
1165
1357
|
);
|
|
1166
1358
|
let closestDist = Infinity;
|
|
1167
1359
|
let closestPair = [-1, -1];
|
|
@@ -1219,6 +1411,7 @@ var createNetsFromProps = (component, props) => {
|
|
|
1219
1411
|
// lib/components/base-components/NormalComponent.ts
|
|
1220
1412
|
var NormalComponent = class extends PrimitiveComponent {
|
|
1221
1413
|
reactSubtrees = [];
|
|
1414
|
+
isPrimitiveContainer = true;
|
|
1222
1415
|
constructor(props) {
|
|
1223
1416
|
super(props);
|
|
1224
1417
|
this._addChildrenFromStringFootprint();
|
|
@@ -1240,6 +1433,7 @@ var NormalComponent = class extends PrimitiveComponent {
|
|
|
1240
1433
|
*/
|
|
1241
1434
|
initPorts() {
|
|
1242
1435
|
const { config } = this;
|
|
1436
|
+
const portsToCreate = [];
|
|
1243
1437
|
if (config.schematicSymbolName) {
|
|
1244
1438
|
const sym = symbols3[`${config.schematicSymbolName}_horz`];
|
|
1245
1439
|
if (!sym) return;
|
|
@@ -1247,27 +1441,31 @@ var NormalComponent = class extends PrimitiveComponent {
|
|
|
1247
1441
|
const port = getPortFromHints(symPort.labels);
|
|
1248
1442
|
if (port) {
|
|
1249
1443
|
port.schematicSymbolPortDef = symPort;
|
|
1250
|
-
|
|
1444
|
+
portsToCreate.push(port);
|
|
1251
1445
|
}
|
|
1252
1446
|
}
|
|
1447
|
+
this.addAll(portsToCreate);
|
|
1253
1448
|
return;
|
|
1254
1449
|
}
|
|
1255
1450
|
const portsFromFootprint = this.getPortsFromFootprint();
|
|
1256
|
-
|
|
1451
|
+
portsToCreate.push(...portsFromFootprint);
|
|
1257
1452
|
const pinLabels = this._parsedProps.pinLabels;
|
|
1258
1453
|
if (pinLabels) {
|
|
1259
1454
|
for (let [pinNumber, label] of Object.entries(pinLabels)) {
|
|
1260
1455
|
pinNumber = pinNumber.replace("pin", "");
|
|
1261
|
-
const
|
|
1262
|
-
|
|
1456
|
+
const existingPort = portsToCreate.find(
|
|
1457
|
+
(p) => p._parsedProps.pinNumber === Number(pinNumber)
|
|
1458
|
+
);
|
|
1459
|
+
if (!existingPort) {
|
|
1263
1460
|
throw new Error(
|
|
1264
1461
|
`Could not find port for pin number ${pinNumber} in chip ${this.getString()}`
|
|
1265
1462
|
);
|
|
1266
1463
|
}
|
|
1267
|
-
|
|
1268
|
-
|
|
1464
|
+
existingPort.externallyAddedAliases.push(label);
|
|
1465
|
+
existingPort.props.name = label;
|
|
1269
1466
|
}
|
|
1270
1467
|
}
|
|
1468
|
+
this.addAll(portsToCreate);
|
|
1271
1469
|
}
|
|
1272
1470
|
_addChildrenFromStringFootprint() {
|
|
1273
1471
|
const { footprint } = this.props;
|
|
@@ -1305,7 +1503,7 @@ var NormalComponent = class extends PrimitiveComponent {
|
|
|
1305
1503
|
doInitialSourceRender() {
|
|
1306
1504
|
const ftype = this.config.sourceFtype;
|
|
1307
1505
|
if (!ftype) return;
|
|
1308
|
-
const { db } = this.
|
|
1506
|
+
const { db } = this.root;
|
|
1309
1507
|
const { _parsedProps: props } = this;
|
|
1310
1508
|
const source_component = db.source_component.insert({
|
|
1311
1509
|
ftype,
|
|
@@ -1322,7 +1520,7 @@ var NormalComponent = class extends PrimitiveComponent {
|
|
|
1322
1520
|
* You can override this method to do more complicated things.
|
|
1323
1521
|
*/
|
|
1324
1522
|
doInitialSchematicComponentRender() {
|
|
1325
|
-
const { db } = this.
|
|
1523
|
+
const { db } = this.root;
|
|
1326
1524
|
const { schematicSymbolName } = this.config;
|
|
1327
1525
|
if (!schematicSymbolName) return;
|
|
1328
1526
|
const symbol_name = `${this.config.schematicSymbolName}_horz`;
|
|
@@ -1341,10 +1539,10 @@ var NormalComponent = class extends PrimitiveComponent {
|
|
|
1341
1539
|
this.schematic_component_id = schematic_component2.schematic_component_id;
|
|
1342
1540
|
}
|
|
1343
1541
|
doInitialPcbComponentRender() {
|
|
1344
|
-
const { db } = this.
|
|
1542
|
+
const { db } = this.root;
|
|
1345
1543
|
const { _parsedProps: props } = this;
|
|
1346
1544
|
const pcb_component = db.pcb_component.insert({
|
|
1347
|
-
center: this.
|
|
1545
|
+
center: this._getGlobalPcbPositionBeforeLayout(),
|
|
1348
1546
|
// width/height are computed in the PcbComponentSizeCalculation phase
|
|
1349
1547
|
width: 0,
|
|
1350
1548
|
height: 0,
|
|
@@ -1360,7 +1558,7 @@ var NormalComponent = class extends PrimitiveComponent {
|
|
|
1360
1558
|
*/
|
|
1361
1559
|
doInitialPcbComponentSizeCalculation() {
|
|
1362
1560
|
if (!this.pcb_component_id) return;
|
|
1363
|
-
const { db } = this.
|
|
1561
|
+
const { db } = this.root;
|
|
1364
1562
|
const { _parsedProps: props } = this;
|
|
1365
1563
|
let minX = Infinity;
|
|
1366
1564
|
let minY = Infinity;
|
|
@@ -1368,7 +1566,7 @@ var NormalComponent = class extends PrimitiveComponent {
|
|
|
1368
1566
|
let maxY = -Infinity;
|
|
1369
1567
|
for (const child of this.children) {
|
|
1370
1568
|
if (child.isPcbPrimitive) {
|
|
1371
|
-
const { x, y } = child.
|
|
1569
|
+
const { x, y } = child._getGlobalPcbPositionBeforeLayout();
|
|
1372
1570
|
const { width: width2, height: height2 } = child.getPcbSize();
|
|
1373
1571
|
minX = Math.min(minX, x - width2 / 2);
|
|
1374
1572
|
minY = Math.min(minY, y - height2 / 2);
|
|
@@ -1389,6 +1587,9 @@ var NormalComponent = class extends PrimitiveComponent {
|
|
|
1389
1587
|
component: createInstanceFromReactElement(element)
|
|
1390
1588
|
};
|
|
1391
1589
|
}
|
|
1590
|
+
doInitialInitializePortsFromChildren() {
|
|
1591
|
+
this.initPorts();
|
|
1592
|
+
}
|
|
1392
1593
|
doInitialReactSubtreesRender() {
|
|
1393
1594
|
if (isReactElement2(this.props.footprint)) {
|
|
1394
1595
|
if (this.reactSubtrees.some((rs) => rs.element === this.props.footprint))
|
|
@@ -1398,6 +1599,16 @@ var NormalComponent = class extends PrimitiveComponent {
|
|
|
1398
1599
|
this.add(subtree.component);
|
|
1399
1600
|
}
|
|
1400
1601
|
}
|
|
1602
|
+
_hasExistingPortExactly(port1) {
|
|
1603
|
+
const existingPorts = this.children.filter(
|
|
1604
|
+
(c) => c.componentName === "Port"
|
|
1605
|
+
);
|
|
1606
|
+
return existingPorts.some((port2) => {
|
|
1607
|
+
const aliases1 = port1.getNameAndAliases();
|
|
1608
|
+
const aliases2 = port2.getNameAndAliases();
|
|
1609
|
+
return aliases1.length === aliases2.length && aliases1.every((alias) => aliases2.includes(alias));
|
|
1610
|
+
});
|
|
1611
|
+
}
|
|
1401
1612
|
add(componentOrElm) {
|
|
1402
1613
|
let component;
|
|
1403
1614
|
if (isReactElement2(componentOrElm)) {
|
|
@@ -1407,6 +1618,20 @@ var NormalComponent = class extends PrimitiveComponent {
|
|
|
1407
1618
|
} else {
|
|
1408
1619
|
component = componentOrElm;
|
|
1409
1620
|
}
|
|
1621
|
+
if (component.componentName === "Port") {
|
|
1622
|
+
if (this._hasExistingPortExactly(component)) return;
|
|
1623
|
+
const existingPorts = this.children.filter(
|
|
1624
|
+
(c) => c.componentName === "Port"
|
|
1625
|
+
);
|
|
1626
|
+
const conflictingPort = existingPorts.find(
|
|
1627
|
+
(p) => p.isMatchingAnyOf(component.getNameAndAliases())
|
|
1628
|
+
);
|
|
1629
|
+
if (conflictingPort) {
|
|
1630
|
+
throw new Error(
|
|
1631
|
+
`Conflicting ports added. Port 1: ${conflictingPort}, Port 2: ${component}`
|
|
1632
|
+
);
|
|
1633
|
+
}
|
|
1634
|
+
}
|
|
1410
1635
|
super.add(component);
|
|
1411
1636
|
}
|
|
1412
1637
|
getPortsFromFootprint() {
|
|
@@ -1434,6 +1659,11 @@ var NormalComponent = class extends PrimitiveComponent {
|
|
|
1434
1659
|
if (!newPort) continue;
|
|
1435
1660
|
newPorts2.push(newPort);
|
|
1436
1661
|
}
|
|
1662
|
+
if (newPorts2.length === 0) {
|
|
1663
|
+
throw new Error(
|
|
1664
|
+
`No ports found in chip ${this} (define a schPortArrangement, a footprint or add portHints to elements of the footprint)`
|
|
1665
|
+
);
|
|
1666
|
+
}
|
|
1437
1667
|
return newPorts2;
|
|
1438
1668
|
}
|
|
1439
1669
|
const newPorts = [];
|
|
@@ -1526,7 +1756,7 @@ var Board = class extends Group {
|
|
|
1526
1756
|
};
|
|
1527
1757
|
}
|
|
1528
1758
|
doInitialPcbComponentRender() {
|
|
1529
|
-
const { db } = this.
|
|
1759
|
+
const { db } = this.root;
|
|
1530
1760
|
const { _parsedProps: props } = this;
|
|
1531
1761
|
if (!props.width || !props.height) {
|
|
1532
1762
|
throw new Error("Board width and height or an outline are required");
|
|
@@ -1539,12 +1769,12 @@ var Board = class extends Group {
|
|
|
1539
1769
|
this.pcb_board_id = pcb_board.pcb_board_id;
|
|
1540
1770
|
}
|
|
1541
1771
|
removePcbComponentRender() {
|
|
1542
|
-
const { db } = this.
|
|
1772
|
+
const { db } = this.root;
|
|
1543
1773
|
if (!this.pcb_board_id) return;
|
|
1544
1774
|
db.pcb_board.delete(this.pcb_board_id);
|
|
1545
1775
|
this.pcb_board_id = null;
|
|
1546
1776
|
}
|
|
1547
|
-
|
|
1777
|
+
_computePcbGlobalTransformBeforeLayout() {
|
|
1548
1778
|
return identity4();
|
|
1549
1779
|
}
|
|
1550
1780
|
};
|
|
@@ -1685,8 +1915,8 @@ var mergeRoutes = (routes) => {
|
|
|
1685
1915
|
|
|
1686
1916
|
// lib/utils/getClosest.ts
|
|
1687
1917
|
var getDistance = (a, b) => {
|
|
1688
|
-
const aPos = "
|
|
1689
|
-
const bPos = "
|
|
1918
|
+
const aPos = "_getGlobalPcbPositionBeforeLayout" in a ? a._getGlobalPcbPositionBeforeLayout() : a;
|
|
1919
|
+
const bPos = "_getGlobalPcbPositionBeforeLayout" in b ? b._getGlobalPcbPositionBeforeLayout() : b;
|
|
1690
1920
|
return Math.sqrt((aPos.x - bPos.x) ** 2 + (aPos.y - bPos.y) ** 2);
|
|
1691
1921
|
};
|
|
1692
1922
|
function getClosest(point, candidates) {
|
|
@@ -1707,7 +1937,7 @@ function getClosest(point, candidates) {
|
|
|
1707
1937
|
// lib/components/primitive-components/Trace.ts
|
|
1708
1938
|
import "zod";
|
|
1709
1939
|
var portToObjective = (port) => {
|
|
1710
|
-
const portPosition = port.
|
|
1940
|
+
const portPosition = port._getGlobalPcbPositionBeforeLayout();
|
|
1711
1941
|
return {
|
|
1712
1942
|
...portPosition,
|
|
1713
1943
|
layers: port.getAvailablePcbLayers()
|
|
@@ -1752,7 +1982,7 @@ var Trace = class extends PrimitiveComponent {
|
|
|
1752
1982
|
);
|
|
1753
1983
|
}
|
|
1754
1984
|
_findConnectedPorts() {
|
|
1755
|
-
const { db } = this.
|
|
1985
|
+
const { db } = this.root;
|
|
1756
1986
|
const { _parsedProps: props, parent } = this;
|
|
1757
1987
|
if (!parent) throw new Error("Trace has no parent");
|
|
1758
1988
|
const portSelectors = this.getTracePortPathSelectors();
|
|
@@ -1836,7 +2066,7 @@ searched component ${targetComponent.getString()}, which has ports: ${targetComp
|
|
|
1836
2066
|
createNetsFromProps(this, this.getTracePathNetSelectors());
|
|
1837
2067
|
}
|
|
1838
2068
|
doInitialSourceTraceRender() {
|
|
1839
|
-
const { db } = this.
|
|
2069
|
+
const { db } = this.root;
|
|
1840
2070
|
const { _parsedProps: props, parent } = this;
|
|
1841
2071
|
if (!parent) {
|
|
1842
2072
|
this.renderError("Trace has no parent");
|
|
@@ -1852,7 +2082,7 @@ searched component ${targetComponent.getString()}, which has ports: ${targetComp
|
|
|
1852
2082
|
this.source_trace_id = trace.source_trace_id;
|
|
1853
2083
|
}
|
|
1854
2084
|
doInitialPcbTraceRender() {
|
|
1855
|
-
const { db } = this.
|
|
2085
|
+
const { db } = this.root;
|
|
1856
2086
|
const { _parsedProps: props, parent } = this;
|
|
1857
2087
|
if (!parent) throw new Error("Trace has no parent");
|
|
1858
2088
|
const { allPortsFound, ports } = this._findConnectedPorts();
|
|
@@ -1933,7 +2163,7 @@ searched component ${targetComponent.getString()}, which has ports: ${targetComp
|
|
|
1933
2163
|
`Could not find a common layer (using hints) for trace ${this.getString()}`
|
|
1934
2164
|
);
|
|
1935
2165
|
}
|
|
1936
|
-
const obstacles = getObstaclesFromSoup(this.
|
|
2166
|
+
const obstacles = getObstaclesFromSoup(this.root.db.toArray());
|
|
1937
2167
|
markObstaclesAsConnected(
|
|
1938
2168
|
obstacles,
|
|
1939
2169
|
orderedRouteObjectives,
|
|
@@ -1999,7 +2229,7 @@ searched component ${targetComponent.getString()}, which has ports: ${targetComp
|
|
|
1999
2229
|
this.pcb_trace_id = pcb_trace.pcb_trace_id;
|
|
2000
2230
|
}
|
|
2001
2231
|
doInitialSchematicTraceRender() {
|
|
2002
|
-
const { db } = this.
|
|
2232
|
+
const { db } = this.root;
|
|
2003
2233
|
const { _parsedProps: props, parent } = this;
|
|
2004
2234
|
if (!parent) throw new Error("Trace has no parent");
|
|
2005
2235
|
const { allPortsFound, portsWithSelectors: ports } = this._findConnectedPorts();
|
|
@@ -2023,7 +2253,7 @@ searched component ${targetComponent.getString()}, which has ports: ${targetComp
|
|
|
2023
2253
|
for (const { port } of ports) {
|
|
2024
2254
|
connection.pointsToConnect.push(
|
|
2025
2255
|
projectPointInDirection(
|
|
2026
|
-
port.
|
|
2256
|
+
port._getGlobalSchematicPositionBeforeLayout(),
|
|
2027
2257
|
port.facingDirection,
|
|
2028
2258
|
0.1501
|
|
2029
2259
|
)
|
|
@@ -2093,7 +2323,7 @@ var Resistor = class extends NormalComponent {
|
|
|
2093
2323
|
}
|
|
2094
2324
|
}
|
|
2095
2325
|
doInitialSourceRender() {
|
|
2096
|
-
const { db } = this.
|
|
2326
|
+
const { db } = this.root;
|
|
2097
2327
|
const { _parsedProps: props } = this;
|
|
2098
2328
|
const source_component = db.source_component.insert({
|
|
2099
2329
|
ftype: "simple_resistor",
|
|
@@ -2171,7 +2401,7 @@ var Capacitor = class extends NormalComponent {
|
|
|
2171
2401
|
}
|
|
2172
2402
|
}
|
|
2173
2403
|
doInitialSourceRender() {
|
|
2174
|
-
const { db } = this.
|
|
2404
|
+
const { db } = this.root;
|
|
2175
2405
|
const { _parsedProps: props } = this;
|
|
2176
2406
|
const source_component = db.source_component.insert({
|
|
2177
2407
|
ftype: "simple_capacitor",
|
|
@@ -2191,7 +2421,7 @@ import { applyToPoint as applyToPoint4 } from "transformation-matrix";
|
|
|
2191
2421
|
var TraceHint = class extends PrimitiveComponent {
|
|
2192
2422
|
matchedPort = null;
|
|
2193
2423
|
doInitialPortMatching() {
|
|
2194
|
-
const { db } = this.
|
|
2424
|
+
const { db } = this.root;
|
|
2195
2425
|
const { _parsedProps: props, parent } = this;
|
|
2196
2426
|
if (!parent) return;
|
|
2197
2427
|
if (parent.componentName === "Trace") {
|
|
@@ -2218,7 +2448,7 @@ var TraceHint = class extends PrimitiveComponent {
|
|
|
2218
2448
|
const { _parsedProps: props } = this;
|
|
2219
2449
|
const offsets = props.offset ? [props.offset] : props.offsets;
|
|
2220
2450
|
if (!offsets) return [];
|
|
2221
|
-
const globalTransform = this.
|
|
2451
|
+
const globalTransform = this._computePcbGlobalTransformBeforeLayout();
|
|
2222
2452
|
return offsets.map(
|
|
2223
2453
|
(offset) => ({
|
|
2224
2454
|
...applyToPoint4(globalTransform, offset),
|
|
@@ -2522,7 +2752,7 @@ var Chip = class extends NormalComponent {
|
|
|
2522
2752
|
};
|
|
2523
2753
|
}
|
|
2524
2754
|
doInitialSourceRender() {
|
|
2525
|
-
const { db } = this.
|
|
2755
|
+
const { db } = this.root;
|
|
2526
2756
|
const { _parsedProps: props } = this;
|
|
2527
2757
|
const source_component = db.source_component.insert({
|
|
2528
2758
|
ftype: "simple_chip",
|
|
@@ -2533,7 +2763,7 @@ var Chip = class extends NormalComponent {
|
|
|
2533
2763
|
this.source_component_id = source_component.source_component_id;
|
|
2534
2764
|
}
|
|
2535
2765
|
doInitialSchematicComponentRender() {
|
|
2536
|
-
const { db } = this.
|
|
2766
|
+
const { db } = this.root;
|
|
2537
2767
|
const { _parsedProps: props } = this;
|
|
2538
2768
|
const ports = this.children.filter((child) => child instanceof Port);
|
|
2539
2769
|
const pinSpacing = props.schPinSpacing ?? 0.2;
|
|
@@ -2565,7 +2795,7 @@ var Chip = class extends NormalComponent {
|
|
|
2565
2795
|
this.schematic_component_id = schematic_component2.schematic_component_id;
|
|
2566
2796
|
}
|
|
2567
2797
|
doInitialPcbComponentRender() {
|
|
2568
|
-
const { db } = this.
|
|
2798
|
+
const { db } = this.root;
|
|
2569
2799
|
const { _parsedProps: props } = this;
|
|
2570
2800
|
const pcb_component = db.pcb_component.insert({
|
|
2571
2801
|
center: { x: props.pcbX ?? 0, y: props.pcbY ?? 0 },
|
|
@@ -2591,7 +2821,7 @@ var Jumper = class extends NormalComponent {
|
|
|
2591
2821
|
};
|
|
2592
2822
|
}
|
|
2593
2823
|
doInitialSourceRender() {
|
|
2594
|
-
const { db } = this.
|
|
2824
|
+
const { db } = this.root;
|
|
2595
2825
|
const { _parsedProps: props } = this;
|
|
2596
2826
|
const source_component = db.source_component.insert({
|
|
2597
2827
|
ftype: "simple_chip",
|
|
@@ -2603,7 +2833,7 @@ var Jumper = class extends NormalComponent {
|
|
|
2603
2833
|
this.source_component_id = source_component.source_component_id;
|
|
2604
2834
|
}
|
|
2605
2835
|
doInitialSchematicComponentRender() {
|
|
2606
|
-
const { db } = this.
|
|
2836
|
+
const { db } = this.root;
|
|
2607
2837
|
const { _parsedProps: props } = this;
|
|
2608
2838
|
const ports = this.children.filter((child) => child instanceof Port);
|
|
2609
2839
|
const pinSpacing = props.schPinSpacing ?? 0.2;
|
|
@@ -2638,7 +2868,7 @@ var Jumper = class extends NormalComponent {
|
|
|
2638
2868
|
this.schematic_component_id = schematic_component2.schematic_component_id;
|
|
2639
2869
|
}
|
|
2640
2870
|
doInitialPcbComponentRender() {
|
|
2641
|
-
const { db } = this.
|
|
2871
|
+
const { db } = this.root;
|
|
2642
2872
|
const { _parsedProps: props } = this;
|
|
2643
2873
|
const pcb_component = db.pcb_component.insert({
|
|
2644
2874
|
center: { x: props.pcbX ?? 0, y: props.pcbY ?? 0 },
|
|
@@ -2654,18 +2884,58 @@ var Jumper = class extends NormalComponent {
|
|
|
2654
2884
|
}
|
|
2655
2885
|
};
|
|
2656
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
|
+
|
|
2657
2924
|
// lib/Project.ts
|
|
2658
2925
|
import { su } from "@tscircuit/soup-util";
|
|
2659
2926
|
import { isValidElement as isValidElement2 } from "react";
|
|
2660
2927
|
import { identity as identity5 } from "transformation-matrix";
|
|
2661
2928
|
var Circuit = class {
|
|
2662
|
-
|
|
2929
|
+
firstChild = null;
|
|
2663
2930
|
children;
|
|
2664
2931
|
db;
|
|
2932
|
+
root = null;
|
|
2933
|
+
isRoot = true;
|
|
2665
2934
|
_hasRenderedAtleastOnce = false;
|
|
2666
2935
|
constructor() {
|
|
2667
2936
|
this.children = [];
|
|
2668
2937
|
this.db = su([]);
|
|
2938
|
+
this.root = this;
|
|
2669
2939
|
}
|
|
2670
2940
|
add(componentOrElm) {
|
|
2671
2941
|
let component;
|
|
@@ -2677,9 +2947,9 @@ var Circuit = class {
|
|
|
2677
2947
|
this.children.push(component);
|
|
2678
2948
|
}
|
|
2679
2949
|
_guessRootComponent() {
|
|
2680
|
-
if (this.
|
|
2950
|
+
if (this.firstChild) return;
|
|
2681
2951
|
if (this.children.length === 1) {
|
|
2682
|
-
this.
|
|
2952
|
+
this.firstChild = this.children[0];
|
|
2683
2953
|
return;
|
|
2684
2954
|
}
|
|
2685
2955
|
if (this.children.length === 0) {
|
|
@@ -2690,7 +2960,7 @@ var Circuit = class {
|
|
|
2690
2960
|
if (this.children.length > 0) {
|
|
2691
2961
|
const board = this.children.find((c) => c.componentName === "Board") ?? null;
|
|
2692
2962
|
if (board) {
|
|
2693
|
-
this.
|
|
2963
|
+
this.firstChild = board;
|
|
2694
2964
|
return;
|
|
2695
2965
|
}
|
|
2696
2966
|
}
|
|
@@ -2699,13 +2969,13 @@ var Circuit = class {
|
|
|
2699
2969
|
);
|
|
2700
2970
|
}
|
|
2701
2971
|
render() {
|
|
2702
|
-
if (!this.
|
|
2972
|
+
if (!this.firstChild) {
|
|
2703
2973
|
this._guessRootComponent();
|
|
2704
2974
|
}
|
|
2705
|
-
const {
|
|
2706
|
-
if (!
|
|
2707
|
-
|
|
2708
|
-
|
|
2975
|
+
const { firstChild, db } = this;
|
|
2976
|
+
if (!firstChild) throw new Error("Project has no root component");
|
|
2977
|
+
firstChild.parent = this;
|
|
2978
|
+
firstChild.runRenderCycle();
|
|
2709
2979
|
this._hasRenderedAtleastOnce = true;
|
|
2710
2980
|
}
|
|
2711
2981
|
getSoup() {
|
|
@@ -2729,17 +2999,17 @@ var Circuit = class {
|
|
|
2729
2999
|
const previewOpts = typeof previewNameOrOpts === "object" ? previewNameOrOpts : { previewName: previewNameOrOpts };
|
|
2730
3000
|
throw new Error("project.preview is not yet implemented");
|
|
2731
3001
|
}
|
|
2732
|
-
|
|
3002
|
+
computeSchematicGlobalTransform() {
|
|
2733
3003
|
return identity5();
|
|
2734
3004
|
}
|
|
2735
|
-
|
|
3005
|
+
_computePcbGlobalTransformBeforeLayout() {
|
|
2736
3006
|
return identity5();
|
|
2737
3007
|
}
|
|
2738
3008
|
selectAll(selector) {
|
|
2739
|
-
return this.
|
|
3009
|
+
return this.firstChild?.selectAll(selector) ?? [];
|
|
2740
3010
|
}
|
|
2741
3011
|
selectOne(selector, opts) {
|
|
2742
|
-
return this.
|
|
3012
|
+
return this.firstChild?.selectOne(selector, opts) ?? null;
|
|
2743
3013
|
}
|
|
2744
3014
|
};
|
|
2745
3015
|
var Project = Circuit;
|
|
@@ -2754,6 +3024,7 @@ export {
|
|
|
2754
3024
|
Capacitor,
|
|
2755
3025
|
Chip,
|
|
2756
3026
|
Circuit,
|
|
3027
|
+
Constraint2 as Constraint,
|
|
2757
3028
|
Footprint,
|
|
2758
3029
|
Group,
|
|
2759
3030
|
Jumper,
|