@tscircuit/core 0.0.98 → 0.0.100
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 +48 -48
- package/dist/index.js +863 -831
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -34,13 +34,12 @@ __export(components_exports, {
|
|
|
34
34
|
TraceHint: () => TraceHint
|
|
35
35
|
});
|
|
36
36
|
|
|
37
|
-
// lib/components/
|
|
38
|
-
import {
|
|
37
|
+
// lib/components/base-components/NormalComponent.ts
|
|
38
|
+
import { rotation } from "circuit-json";
|
|
39
|
+
import { fp } from "footprinter";
|
|
39
40
|
|
|
40
|
-
// lib/
|
|
41
|
-
import
|
|
42
|
-
import { symbols } from "schematic-symbols";
|
|
43
|
-
import "react";
|
|
41
|
+
// lib/fiber/create-instance-from-react-element.ts
|
|
42
|
+
import ReactReconciler from "react-reconciler";
|
|
44
43
|
|
|
45
44
|
// lib/components/base-components/Renderable.ts
|
|
46
45
|
var orderedRenderPhases = [
|
|
@@ -133,12 +132,169 @@ var Renderable = class {
|
|
|
133
132
|
}
|
|
134
133
|
};
|
|
135
134
|
|
|
135
|
+
// lib/fiber/catalogue.ts
|
|
136
|
+
var catalogue = {};
|
|
137
|
+
var extendCatalogue = (objects) => {
|
|
138
|
+
const altKeys = Object.fromEntries(
|
|
139
|
+
Object.entries(objects).map(([key, v]) => [key.toLowerCase(), v])
|
|
140
|
+
);
|
|
141
|
+
Object.assign(catalogue, objects);
|
|
142
|
+
Object.assign(catalogue, altKeys);
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
// lib/fiber/create-instance-from-react-element.ts
|
|
146
|
+
import { identity } from "transformation-matrix";
|
|
147
|
+
function prepare(object, state) {
|
|
148
|
+
const instance = object;
|
|
149
|
+
instance.__tsci = {
|
|
150
|
+
...state
|
|
151
|
+
};
|
|
152
|
+
return object;
|
|
153
|
+
}
|
|
154
|
+
var hostConfig = {
|
|
155
|
+
supportsMutation: true,
|
|
156
|
+
createInstance(type, props) {
|
|
157
|
+
const target = catalogue[type];
|
|
158
|
+
if (!target) {
|
|
159
|
+
if (Object.keys(catalogue).length === 0) {
|
|
160
|
+
throw new Error(
|
|
161
|
+
"No components registered in catalogue, did you forget to import lib/register-catalogue in your test file?"
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
throw new Error(
|
|
165
|
+
`Unsupported component type (not registered in @tscircuit/core catalogue): "${type}" See CREATING_NEW_COMPONENTS.md`
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
const instance = prepare(new target(props), {});
|
|
169
|
+
return instance;
|
|
170
|
+
},
|
|
171
|
+
createTextInstance() {
|
|
172
|
+
return {};
|
|
173
|
+
},
|
|
174
|
+
appendInitialChild(parentInstance, child) {
|
|
175
|
+
parentInstance.add(child);
|
|
176
|
+
},
|
|
177
|
+
appendChild(parentInstance, child) {
|
|
178
|
+
parentInstance.add(child);
|
|
179
|
+
},
|
|
180
|
+
appendChildToContainer(container, child) {
|
|
181
|
+
container.add(child);
|
|
182
|
+
},
|
|
183
|
+
finalizeInitialChildren() {
|
|
184
|
+
return false;
|
|
185
|
+
},
|
|
186
|
+
prepareUpdate() {
|
|
187
|
+
return null;
|
|
188
|
+
},
|
|
189
|
+
shouldSetTextContent() {
|
|
190
|
+
return false;
|
|
191
|
+
},
|
|
192
|
+
getRootHostContext() {
|
|
193
|
+
return {};
|
|
194
|
+
},
|
|
195
|
+
getChildHostContext() {
|
|
196
|
+
return {};
|
|
197
|
+
},
|
|
198
|
+
prepareForCommit() {
|
|
199
|
+
return null;
|
|
200
|
+
},
|
|
201
|
+
resetAfterCommit() {
|
|
202
|
+
},
|
|
203
|
+
commitMount() {
|
|
204
|
+
},
|
|
205
|
+
commitUpdate() {
|
|
206
|
+
},
|
|
207
|
+
removeChild() {
|
|
208
|
+
},
|
|
209
|
+
clearContainer() {
|
|
210
|
+
},
|
|
211
|
+
supportsPersistence: false,
|
|
212
|
+
getPublicInstance(instance) {
|
|
213
|
+
return instance;
|
|
214
|
+
},
|
|
215
|
+
preparePortalMount(containerInfo) {
|
|
216
|
+
throw new Error("Function not implemented.");
|
|
217
|
+
},
|
|
218
|
+
scheduleTimeout(fn, delay) {
|
|
219
|
+
throw new Error("Function not implemented.");
|
|
220
|
+
},
|
|
221
|
+
cancelTimeout(id) {
|
|
222
|
+
throw new Error("Function not implemented.");
|
|
223
|
+
},
|
|
224
|
+
noTimeout: void 0,
|
|
225
|
+
isPrimaryRenderer: false,
|
|
226
|
+
getCurrentEventPriority() {
|
|
227
|
+
throw new Error("Function not implemented.");
|
|
228
|
+
},
|
|
229
|
+
getInstanceFromNode(node) {
|
|
230
|
+
throw new Error("Function not implemented.");
|
|
231
|
+
},
|
|
232
|
+
beforeActiveInstanceBlur() {
|
|
233
|
+
throw new Error("Function not implemented.");
|
|
234
|
+
},
|
|
235
|
+
afterActiveInstanceBlur() {
|
|
236
|
+
throw new Error("Function not implemented.");
|
|
237
|
+
},
|
|
238
|
+
prepareScopeUpdate: (scopeInstance, instance) => {
|
|
239
|
+
throw new Error("Function not implemented.");
|
|
240
|
+
},
|
|
241
|
+
getInstanceFromScope: (scopeInstance) => {
|
|
242
|
+
throw new Error("Function not implemented.");
|
|
243
|
+
},
|
|
244
|
+
detachDeletedInstance: (node) => {
|
|
245
|
+
throw new Error("Function not implemented.");
|
|
246
|
+
},
|
|
247
|
+
supportsHydration: false
|
|
248
|
+
};
|
|
249
|
+
var reconciler = ReactReconciler(hostConfig);
|
|
250
|
+
var createInstanceFromReactElement = (reactElm) => {
|
|
251
|
+
const rootContainer = {
|
|
252
|
+
children: [],
|
|
253
|
+
props: {
|
|
254
|
+
name: "$root"
|
|
255
|
+
},
|
|
256
|
+
add(instance) {
|
|
257
|
+
instance.parent = this;
|
|
258
|
+
this.children.push(instance);
|
|
259
|
+
},
|
|
260
|
+
computePcbGlobalTransform() {
|
|
261
|
+
return identity();
|
|
262
|
+
}
|
|
263
|
+
};
|
|
264
|
+
const container = reconciler.createContainer(
|
|
265
|
+
// TODO Replace with store like react-three-fiber
|
|
266
|
+
// https://github.com/pmndrs/react-three-fiber/blob/a457290856f57741bf8beef4f6ff9dbf4879c0a5/packages/fiber/src/core/index.tsx#L172
|
|
267
|
+
// https://github.com/pmndrs/react-three-fiber/blob/master/packages/fiber/src/core/store.ts#L168
|
|
268
|
+
rootContainer,
|
|
269
|
+
0,
|
|
270
|
+
null,
|
|
271
|
+
false,
|
|
272
|
+
null,
|
|
273
|
+
"tsci",
|
|
274
|
+
(error) => {
|
|
275
|
+
console.log("Error in createContainer");
|
|
276
|
+
console.error(error);
|
|
277
|
+
},
|
|
278
|
+
null
|
|
279
|
+
);
|
|
280
|
+
reconciler.updateContainer(reactElm, container, null, () => {
|
|
281
|
+
});
|
|
282
|
+
const rootInstance = reconciler.getPublicRootInstance(
|
|
283
|
+
container
|
|
284
|
+
);
|
|
285
|
+
if (rootInstance) return rootInstance;
|
|
286
|
+
return rootContainer.children[0];
|
|
287
|
+
};
|
|
288
|
+
|
|
136
289
|
// lib/components/base-components/PrimitiveComponent.ts
|
|
290
|
+
import { z } from "zod";
|
|
291
|
+
import { symbols } from "schematic-symbols";
|
|
292
|
+
import "react";
|
|
137
293
|
import {
|
|
138
294
|
applyToPoint,
|
|
139
295
|
compose,
|
|
140
296
|
flipY,
|
|
141
|
-
identity,
|
|
297
|
+
identity as identity2,
|
|
142
298
|
rotate,
|
|
143
299
|
translate
|
|
144
300
|
} from "transformation-matrix";
|
|
@@ -267,7 +423,7 @@ var PrimitiveComponent = class extends Renderable {
|
|
|
267
423
|
const manualPlacement = this.getSubcircuit()._getManualPlacementForComponent(this);
|
|
268
424
|
if (manualPlacement && this.props.pcbX === void 0 && this.props.pcbY === void 0) {
|
|
269
425
|
return compose(
|
|
270
|
-
this.parent?._computePcbGlobalTransformBeforeLayout() ??
|
|
426
|
+
this.parent?._computePcbGlobalTransformBeforeLayout() ?? identity2(),
|
|
271
427
|
compose(
|
|
272
428
|
translate(manualPlacement.x, manualPlacement.y),
|
|
273
429
|
rotate((props.pcbRotation ?? 0) * Math.PI / 180)
|
|
@@ -286,7 +442,7 @@ var PrimitiveComponent = class extends Renderable {
|
|
|
286
442
|
translate(-containerCenter.x, -containerCenter.y)
|
|
287
443
|
);
|
|
288
444
|
return compose(
|
|
289
|
-
this.parent?._computePcbGlobalTransformBeforeLayout() ??
|
|
445
|
+
this.parent?._computePcbGlobalTransformBeforeLayout() ?? identity2(),
|
|
290
446
|
flipY(),
|
|
291
447
|
this.computePcbPropsTransform()
|
|
292
448
|
);
|
|
@@ -294,7 +450,7 @@ var PrimitiveComponent = class extends Renderable {
|
|
|
294
450
|
}
|
|
295
451
|
}
|
|
296
452
|
return compose(
|
|
297
|
-
this.parent?._computePcbGlobalTransformBeforeLayout() ??
|
|
453
|
+
this.parent?._computePcbGlobalTransformBeforeLayout() ?? identity2(),
|
|
298
454
|
this.computePcbPropsTransform()
|
|
299
455
|
);
|
|
300
456
|
}
|
|
@@ -356,7 +512,7 @@ var PrimitiveComponent = class extends Renderable {
|
|
|
356
512
|
*/
|
|
357
513
|
computeSchematicGlobalTransform() {
|
|
358
514
|
return compose(
|
|
359
|
-
this.parent?.computeSchematicGlobalTransform?.() ??
|
|
515
|
+
this.parent?.computeSchematicGlobalTransform?.() ?? identity2(),
|
|
360
516
|
this.computeSchematicPropsTransform()
|
|
361
517
|
);
|
|
362
518
|
}
|
|
@@ -566,603 +722,166 @@ var PrimitiveComponent = class extends Renderable {
|
|
|
566
722
|
}
|
|
567
723
|
};
|
|
568
724
|
|
|
569
|
-
// lib/components/primitive-components/
|
|
570
|
-
import
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
725
|
+
// lib/components/primitive-components/Net.ts
|
|
726
|
+
import { z as z2 } from "zod";
|
|
727
|
+
|
|
728
|
+
// lib/utils/pairs.ts
|
|
729
|
+
function pairs(arr) {
|
|
730
|
+
const result = [];
|
|
731
|
+
for (let i = 0; i < arr.length - 1; i++) {
|
|
732
|
+
result.push([arr[i], arr[i + 1]]);
|
|
733
|
+
}
|
|
734
|
+
return result;
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
// lib/components/primitive-components/Net.ts
|
|
738
|
+
import { autoroute } from "@tscircuit/infgrid-ijump-astar";
|
|
739
|
+
var netProps = z2.object({
|
|
740
|
+
name: z2.string()
|
|
741
|
+
});
|
|
742
|
+
var Net = class extends PrimitiveComponent {
|
|
743
|
+
source_net_id;
|
|
574
744
|
get config() {
|
|
575
745
|
return {
|
|
576
|
-
componentName: "
|
|
577
|
-
zodProps:
|
|
746
|
+
componentName: "Net",
|
|
747
|
+
zodProps: netProps
|
|
578
748
|
};
|
|
579
749
|
}
|
|
750
|
+
getPortSelector() {
|
|
751
|
+
return `net.${this.props.name}`;
|
|
752
|
+
}
|
|
753
|
+
doInitialSourceRender() {
|
|
754
|
+
const { db } = this.root;
|
|
755
|
+
const { _parsedProps: props } = this;
|
|
756
|
+
const net = db.source_net.insert({
|
|
757
|
+
name: props.name,
|
|
758
|
+
member_source_group_ids: []
|
|
759
|
+
});
|
|
760
|
+
this.source_net_id = net.source_net_id;
|
|
761
|
+
}
|
|
580
762
|
/**
|
|
581
|
-
*
|
|
582
|
-
*
|
|
763
|
+
* Get all ports connected to this net.
|
|
764
|
+
*
|
|
765
|
+
* TODO currently we're not checking for indirect connections (traces that are
|
|
766
|
+
* connected to other traces that are in turn connected to the net)
|
|
583
767
|
*/
|
|
584
|
-
|
|
585
|
-
const
|
|
586
|
-
|
|
587
|
-
)
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
return {
|
|
594
|
-
...props,
|
|
595
|
-
left: props.right,
|
|
596
|
-
right: props.left
|
|
597
|
-
};
|
|
768
|
+
getAllConnectedPorts() {
|
|
769
|
+
const allPorts = this.getSubcircuit().selectAll("port");
|
|
770
|
+
const connectedPorts = [];
|
|
771
|
+
for (const port of allPorts) {
|
|
772
|
+
const traces = port._getDirectlyConnectedTraces();
|
|
773
|
+
for (const trace of traces) {
|
|
774
|
+
if (trace._isExplicitlyConnectedToNet(this)) {
|
|
775
|
+
connectedPorts.push(port);
|
|
776
|
+
break;
|
|
598
777
|
}
|
|
599
778
|
}
|
|
600
|
-
return props;
|
|
601
|
-
};
|
|
602
|
-
const involvedComponents = constraints.flatMap(
|
|
603
|
-
(constraint) => constraint._getAllReferencedComponents().componentsWithSelectors
|
|
604
|
-
).map(({ component, selector, componentSelector, edge }) => ({
|
|
605
|
-
component,
|
|
606
|
-
selector,
|
|
607
|
-
componentSelector,
|
|
608
|
-
edge,
|
|
609
|
-
bounds: component._getPcbCircuitJsonBounds()
|
|
610
|
-
}));
|
|
611
|
-
if (involvedComponents.some((c) => c.edge)) {
|
|
612
|
-
throw new Error(
|
|
613
|
-
"edge constraints not implemented yet for footprint layout, contributions welcome!"
|
|
614
|
-
);
|
|
615
|
-
}
|
|
616
|
-
function getComponentDetails(selector) {
|
|
617
|
-
return involvedComponents.find(({ selector: s }) => s === selector);
|
|
618
|
-
}
|
|
619
|
-
const solver = new kiwi.Solver();
|
|
620
|
-
const kVars = {};
|
|
621
|
-
function getKVar(name) {
|
|
622
|
-
if (!(name in kVars)) {
|
|
623
|
-
kVars[name] = new kiwi.Variable(name);
|
|
624
|
-
solver.addEditVariable(kVars[name], kiwi.Strength.weak);
|
|
625
|
-
}
|
|
626
|
-
return kVars[name];
|
|
627
|
-
}
|
|
628
|
-
for (const { selector, bounds: bounds2 } of involvedComponents) {
|
|
629
|
-
const kvx = getKVar(`${selector}_x`);
|
|
630
|
-
const kvy = getKVar(`${selector}_y`);
|
|
631
|
-
solver.suggestValue(kvx, bounds2.center.x);
|
|
632
|
-
solver.suggestValue(kvy, bounds2.center.y);
|
|
633
|
-
}
|
|
634
|
-
for (const constraint of constraints) {
|
|
635
|
-
const props = constraint._parsedProps;
|
|
636
|
-
if ("xDist" in props) {
|
|
637
|
-
const { xDist, left, right, edgeToEdge, centerToCenter } = maybeFlipLeftRight(props);
|
|
638
|
-
const leftVar = getKVar(`${left}_x`);
|
|
639
|
-
const rightVar = getKVar(`${right}_x`);
|
|
640
|
-
const leftBounds = getComponentDetails(left)?.bounds;
|
|
641
|
-
const rightBounds = getComponentDetails(right)?.bounds;
|
|
642
|
-
if (centerToCenter) {
|
|
643
|
-
const expr = new kiwi.Expression(rightVar, [-1, leftVar]);
|
|
644
|
-
solver.addConstraint(
|
|
645
|
-
new kiwi.Constraint(
|
|
646
|
-
expr,
|
|
647
|
-
kiwi.Operator.Eq,
|
|
648
|
-
props.xDist,
|
|
649
|
-
kiwi.Strength.required
|
|
650
|
-
)
|
|
651
|
-
);
|
|
652
|
-
} else if (edgeToEdge) {
|
|
653
|
-
const expr = new kiwi.Expression(
|
|
654
|
-
rightVar,
|
|
655
|
-
-rightBounds.width / 2,
|
|
656
|
-
[-1, leftVar],
|
|
657
|
-
-leftBounds.width / 2
|
|
658
|
-
);
|
|
659
|
-
solver.addConstraint(
|
|
660
|
-
new kiwi.Constraint(
|
|
661
|
-
expr,
|
|
662
|
-
kiwi.Operator.Eq,
|
|
663
|
-
props.xDist,
|
|
664
|
-
kiwi.Strength.required
|
|
665
|
-
)
|
|
666
|
-
);
|
|
667
|
-
}
|
|
668
|
-
} else if ("yDist" in props) {
|
|
669
|
-
const { yDist, top, bottom, edgeToEdge, centerToCenter } = props;
|
|
670
|
-
const topVar = getKVar(`${top}_y`);
|
|
671
|
-
const bottomVar = getKVar(`${bottom}_y`);
|
|
672
|
-
const topBounds = getComponentDetails(top)?.bounds;
|
|
673
|
-
const bottomBounds = getComponentDetails(bottom)?.bounds;
|
|
674
|
-
if (centerToCenter) {
|
|
675
|
-
const expr = new kiwi.Expression(topVar, [-1, bottomVar]);
|
|
676
|
-
solver.addConstraint(
|
|
677
|
-
new kiwi.Constraint(
|
|
678
|
-
expr,
|
|
679
|
-
kiwi.Operator.Eq,
|
|
680
|
-
props.yDist,
|
|
681
|
-
kiwi.Strength.required
|
|
682
|
-
)
|
|
683
|
-
);
|
|
684
|
-
} else if (edgeToEdge) {
|
|
685
|
-
const expr = new kiwi.Expression(
|
|
686
|
-
topVar,
|
|
687
|
-
topBounds.height / 2,
|
|
688
|
-
[-1, bottomVar],
|
|
689
|
-
-bottomBounds.height / 2
|
|
690
|
-
);
|
|
691
|
-
solver.addConstraint(
|
|
692
|
-
new kiwi.Constraint(
|
|
693
|
-
expr,
|
|
694
|
-
kiwi.Operator.Eq,
|
|
695
|
-
props.yDist,
|
|
696
|
-
kiwi.Strength.required
|
|
697
|
-
)
|
|
698
|
-
);
|
|
699
|
-
}
|
|
700
|
-
} else if ("sameY" in props) {
|
|
701
|
-
const { for: selectors } = props;
|
|
702
|
-
if (selectors.length < 2) continue;
|
|
703
|
-
const vars = selectors.map((selector) => getKVar(`${selector}_y`));
|
|
704
|
-
const expr = new kiwi.Expression(...vars.slice(1));
|
|
705
|
-
solver.addConstraint(
|
|
706
|
-
new kiwi.Constraint(
|
|
707
|
-
expr,
|
|
708
|
-
kiwi.Operator.Eq,
|
|
709
|
-
vars[0],
|
|
710
|
-
kiwi.Strength.required
|
|
711
|
-
)
|
|
712
|
-
);
|
|
713
|
-
} else if ("sameX" in props) {
|
|
714
|
-
const { for: selectors } = props;
|
|
715
|
-
if (selectors.length < 2) continue;
|
|
716
|
-
const vars = selectors.map((selector) => getKVar(`${selector}_x`));
|
|
717
|
-
const expr = new kiwi.Expression(...vars.slice(1));
|
|
718
|
-
solver.addConstraint(
|
|
719
|
-
new kiwi.Constraint(
|
|
720
|
-
expr,
|
|
721
|
-
kiwi.Operator.Eq,
|
|
722
|
-
vars[0],
|
|
723
|
-
kiwi.Strength.required
|
|
724
|
-
)
|
|
725
|
-
);
|
|
726
|
-
}
|
|
727
|
-
}
|
|
728
|
-
solver.updateVariables();
|
|
729
|
-
if (debug.enabled) {
|
|
730
|
-
console.log("Solution to layout constraints:");
|
|
731
|
-
console.table(
|
|
732
|
-
Object.entries(kVars).map(([key, kvar]) => ({
|
|
733
|
-
var: key,
|
|
734
|
-
val: kvar.value()
|
|
735
|
-
}))
|
|
736
|
-
);
|
|
737
|
-
}
|
|
738
|
-
const bounds = {
|
|
739
|
-
left: Infinity,
|
|
740
|
-
right: -Infinity,
|
|
741
|
-
top: -Infinity,
|
|
742
|
-
bottom: Infinity
|
|
743
|
-
};
|
|
744
|
-
for (const {
|
|
745
|
-
selector,
|
|
746
|
-
bounds: { width, height }
|
|
747
|
-
} of involvedComponents) {
|
|
748
|
-
const kvx = getKVar(`${selector}_x`);
|
|
749
|
-
const kvy = getKVar(`${selector}_y`);
|
|
750
|
-
const newLeft = kvx.value() - width / 2;
|
|
751
|
-
const newRight = kvx.value() + width / 2;
|
|
752
|
-
const newTop = kvy.value() + height / 2;
|
|
753
|
-
const newBottom = kvy.value() - height / 2;
|
|
754
|
-
bounds.left = Math.min(bounds.left, newLeft);
|
|
755
|
-
bounds.right = Math.max(bounds.right, newRight);
|
|
756
|
-
bounds.top = Math.max(bounds.top, newTop);
|
|
757
|
-
bounds.bottom = Math.min(bounds.bottom, newBottom);
|
|
758
|
-
}
|
|
759
|
-
const globalOffset = {
|
|
760
|
-
x: -(bounds.right + bounds.left) / 2,
|
|
761
|
-
y: -(bounds.top + bounds.bottom) / 2
|
|
762
|
-
};
|
|
763
|
-
const containerPos = this.getPrimitiveContainer()._getGlobalPcbPositionBeforeLayout();
|
|
764
|
-
globalOffset.x += containerPos.x;
|
|
765
|
-
globalOffset.y += containerPos.y;
|
|
766
|
-
for (const { component, selector } of involvedComponents) {
|
|
767
|
-
const kvx = getKVar(`${selector}_x`);
|
|
768
|
-
const kvy = getKVar(`${selector}_y`);
|
|
769
|
-
component._setPositionFromLayout({
|
|
770
|
-
x: kvx.value() + globalOffset.x,
|
|
771
|
-
y: kvy.value() + globalOffset.y
|
|
772
|
-
});
|
|
773
|
-
}
|
|
774
|
-
}
|
|
775
|
-
};
|
|
776
|
-
|
|
777
|
-
// lib/components/base-components/NormalComponent.ts
|
|
778
|
-
import { z as z4 } from "zod";
|
|
779
|
-
|
|
780
|
-
// lib/utils/get-relative-direction.ts
|
|
781
|
-
function getRelativeDirection(pointA, pointB) {
|
|
782
|
-
const dx = pointB.x - pointA.x;
|
|
783
|
-
const dy = pointB.y - pointA.y;
|
|
784
|
-
if (Math.abs(dx) > Math.abs(dy)) {
|
|
785
|
-
return dx > 0 ? "right" : "left";
|
|
786
|
-
}
|
|
787
|
-
return dy > 0 ? "down" : "up";
|
|
788
|
-
}
|
|
789
|
-
|
|
790
|
-
// lib/components/primitive-components/Port.ts
|
|
791
|
-
import "schematic-symbols";
|
|
792
|
-
import { applyToPoint as applyToPoint2, compose as compose2, translate as translate2 } from "transformation-matrix";
|
|
793
|
-
import { z as z2 } from "zod";
|
|
794
|
-
var portProps = z2.object({
|
|
795
|
-
name: z2.string().optional(),
|
|
796
|
-
pinNumber: z2.number().optional(),
|
|
797
|
-
aliases: z2.array(z2.string()).optional()
|
|
798
|
-
});
|
|
799
|
-
var Port = class extends PrimitiveComponent {
|
|
800
|
-
source_port_id = null;
|
|
801
|
-
pcb_port_id = null;
|
|
802
|
-
schematic_port_id = null;
|
|
803
|
-
schematicSymbolPortDef = null;
|
|
804
|
-
matchedComponents;
|
|
805
|
-
facingDirection = null;
|
|
806
|
-
get config() {
|
|
807
|
-
return {
|
|
808
|
-
componentName: "Port",
|
|
809
|
-
zodProps: portProps
|
|
810
|
-
};
|
|
811
|
-
}
|
|
812
|
-
constructor(props) {
|
|
813
|
-
if (!props.name && props.pinNumber) props.name = `pin${props.pinNumber}`;
|
|
814
|
-
if (!props.name) {
|
|
815
|
-
throw new Error("Port must have a name or a pinNumber");
|
|
816
|
-
}
|
|
817
|
-
super(props);
|
|
818
|
-
this.matchedComponents = [];
|
|
819
|
-
}
|
|
820
|
-
_getGlobalPcbPositionBeforeLayout() {
|
|
821
|
-
const matchedPcbElm = this.matchedComponents.find((c) => c.isPcbPrimitive);
|
|
822
|
-
if (!matchedPcbElm) {
|
|
823
|
-
throw new Error(
|
|
824
|
-
`Port ${this} has no matched pcb component, can't get global schematic position`
|
|
825
|
-
);
|
|
826
|
-
}
|
|
827
|
-
return matchedPcbElm?._getGlobalPcbPositionBeforeLayout() ?? { x: 0, y: 0 };
|
|
828
|
-
}
|
|
829
|
-
_getPcbCircuitJsonBounds() {
|
|
830
|
-
if (!this.pcb_port_id) {
|
|
831
|
-
return super._getPcbCircuitJsonBounds();
|
|
832
|
-
}
|
|
833
|
-
const { db } = this.root;
|
|
834
|
-
const pcb_port = db.pcb_port.get(this.pcb_port_id);
|
|
835
|
-
return {
|
|
836
|
-
center: { x: pcb_port.x, y: pcb_port.y },
|
|
837
|
-
bounds: { left: 0, top: 0, right: 0, bottom: 0 },
|
|
838
|
-
width: 0,
|
|
839
|
-
height: 0
|
|
840
|
-
};
|
|
841
|
-
}
|
|
842
|
-
_getGlobalPcbPositionAfterLayout() {
|
|
843
|
-
return this._getPcbCircuitJsonBounds().center;
|
|
844
|
-
}
|
|
845
|
-
_getGlobalSchematicPositionBeforeLayout() {
|
|
846
|
-
if (!this.schematicSymbolPortDef) {
|
|
847
|
-
return applyToPoint2(this.parent.computeSchematicGlobalTransform(), {
|
|
848
|
-
x: 0,
|
|
849
|
-
y: 0
|
|
850
|
-
});
|
|
851
|
-
}
|
|
852
|
-
const symbol = this.parent?.getSchematicSymbol();
|
|
853
|
-
if (!symbol) {
|
|
854
|
-
console.warn(`Could not find parent symbol for ${this}`);
|
|
855
|
-
return { x: 0, y: 0 };
|
|
856
|
-
}
|
|
857
|
-
const transform = compose2(
|
|
858
|
-
this.parent.computeSchematicGlobalTransform(),
|
|
859
|
-
translate2(-symbol.center.x, -symbol.center.y)
|
|
860
|
-
);
|
|
861
|
-
return applyToPoint2(transform, this.schematicSymbolPortDef);
|
|
862
|
-
}
|
|
863
|
-
/**
|
|
864
|
-
* Smtpads and platedholes call this method to register themselves as a match
|
|
865
|
-
* for this port. All the matching is done by primitives other than the Port,
|
|
866
|
-
* but everyone registers themselves as a match with their Port.
|
|
867
|
-
*/
|
|
868
|
-
registerMatch(component) {
|
|
869
|
-
this.matchedComponents.push(component);
|
|
870
|
-
}
|
|
871
|
-
getNameAndAliases() {
|
|
872
|
-
const { _parsedProps: props } = this;
|
|
873
|
-
return Array.from(
|
|
874
|
-
/* @__PURE__ */ new Set([
|
|
875
|
-
...props.aliases ?? [],
|
|
876
|
-
props.name,
|
|
877
|
-
...typeof props.pinNumber === "number" ? [`pin${props.pinNumber}`, props.pinNumber.toString()] : [],
|
|
878
|
-
...this.externallyAddedAliases
|
|
879
|
-
])
|
|
880
|
-
);
|
|
881
|
-
}
|
|
882
|
-
isMatchingPort(port) {
|
|
883
|
-
return this.isMatchingAnyOf(port.getNameAndAliases());
|
|
884
|
-
}
|
|
885
|
-
getPortSelector() {
|
|
886
|
-
return `.${this.parent?.props.name} > port.${this.props.name}`;
|
|
887
|
-
}
|
|
888
|
-
getAvailablePcbLayers() {
|
|
889
|
-
return Array.from(
|
|
890
|
-
new Set(this.matchedComponents.flatMap((c) => c.getAvailablePcbLayers()))
|
|
891
|
-
);
|
|
892
|
-
}
|
|
893
|
-
/**
|
|
894
|
-
* Return traces that are explicitly connected to this port (not via a net)
|
|
895
|
-
*/
|
|
896
|
-
_getDirectlyConnectedTraces() {
|
|
897
|
-
const allSubcircuitTraces = this.getSubcircuit().selectAll(
|
|
898
|
-
"trace"
|
|
899
|
-
);
|
|
900
|
-
const connectedTraces = allSubcircuitTraces.filter(
|
|
901
|
-
(trace) => trace._isExplicitlyConnectedToPort(this)
|
|
902
|
-
);
|
|
903
|
-
return connectedTraces;
|
|
904
|
-
}
|
|
905
|
-
doInitialSourceRender() {
|
|
906
|
-
const { db } = this.root;
|
|
907
|
-
const { _parsedProps: props } = this;
|
|
908
|
-
const port_hints = this.getNameAndAliases();
|
|
909
|
-
const source_port = db.source_port.insert({
|
|
910
|
-
name: props.name,
|
|
911
|
-
pin_number: props.pinNumber,
|
|
912
|
-
port_hints,
|
|
913
|
-
source_component_id: this.parent?.source_component_id
|
|
914
|
-
});
|
|
915
|
-
this.source_port_id = source_port.source_port_id;
|
|
916
|
-
}
|
|
917
|
-
doInitialSourceParentAttachment() {
|
|
918
|
-
const { db } = this.root;
|
|
919
|
-
if (!this.parent?.source_component_id) {
|
|
920
|
-
throw new Error(
|
|
921
|
-
`${this.getString()} has no parent source component (parent: ${this.parent?.getString()})`
|
|
922
|
-
);
|
|
923
|
-
}
|
|
924
|
-
db.source_port.update(this.source_port_id, {
|
|
925
|
-
source_component_id: this.parent?.source_component_id
|
|
926
|
-
});
|
|
927
|
-
this.source_component_id = this.parent?.source_component_id;
|
|
928
|
-
}
|
|
929
|
-
doInitialPcbPortRender() {
|
|
930
|
-
const { db } = this.root;
|
|
931
|
-
const { matchedComponents } = this;
|
|
932
|
-
if (!this.parent?.pcb_component_id) {
|
|
933
|
-
throw new Error(
|
|
934
|
-
`${this.getString()} has no parent pcb component, cannot render pcb_port (parent: ${this.parent?.getString()})`
|
|
935
|
-
);
|
|
936
|
-
}
|
|
937
|
-
const pcbMatches = matchedComponents.filter((c) => c.isPcbPrimitive);
|
|
938
|
-
if (pcbMatches.length === 0) return;
|
|
939
|
-
if (pcbMatches.length > 1) {
|
|
940
|
-
throw new Error(
|
|
941
|
-
`${this.getString()} has multiple pcb matches, unclear how to place pcb_port: ${pcbMatches.map((c) => c.getString()).join(", ")}`
|
|
942
|
-
);
|
|
943
|
-
}
|
|
944
|
-
const pcbMatch = pcbMatches[0];
|
|
945
|
-
if ("_getPcbCircuitJsonBounds" in pcbMatch) {
|
|
946
|
-
const pcb_port = db.pcb_port.insert({
|
|
947
|
-
pcb_component_id: this.parent?.pcb_component_id,
|
|
948
|
-
layers: this.getAvailablePcbLayers(),
|
|
949
|
-
...pcbMatch._getPcbCircuitJsonBounds().center,
|
|
950
|
-
source_port_id: this.source_port_id
|
|
951
|
-
});
|
|
952
|
-
this.pcb_port_id = pcb_port.pcb_port_id;
|
|
953
|
-
} else {
|
|
954
|
-
throw new Error(
|
|
955
|
-
`${pcbMatch.getString()} does not have a _getGlobalPcbPositionBeforeLayout method (needed for pcb_port placement)`
|
|
956
|
-
);
|
|
957
779
|
}
|
|
780
|
+
return connectedPorts;
|
|
958
781
|
}
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
782
|
+
/**
|
|
783
|
+
* Get all traces that are directly connected to this net, i.e. they list
|
|
784
|
+
* this net in their path, from, or to props
|
|
785
|
+
*/
|
|
786
|
+
_getAllDirectlyConnectedTraces() {
|
|
787
|
+
const allTraces = this.getSubcircuit().selectAll("trace");
|
|
788
|
+
const connectedTraces = [];
|
|
789
|
+
for (const trace of allTraces) {
|
|
790
|
+
if (trace._isExplicitlyConnectedToNet(this)) {
|
|
791
|
+
connectedTraces.push(trace);
|
|
792
|
+
}
|
|
968
793
|
}
|
|
969
|
-
|
|
970
|
-
this.facingDirection = getRelativeDirection(containerCenter, center);
|
|
971
|
-
const schematic_port = db.schematic_port.insert({
|
|
972
|
-
schematic_component_id: this.parent?.schematic_component_id,
|
|
973
|
-
center,
|
|
974
|
-
source_port_id: this.source_port_id,
|
|
975
|
-
facing_direction: this.facingDirection
|
|
976
|
-
});
|
|
977
|
-
this.schematic_port_id = schematic_port.schematic_port_id;
|
|
794
|
+
return connectedTraces;
|
|
978
795
|
}
|
|
979
|
-
|
|
796
|
+
/**
|
|
797
|
+
* Add PCB Traces to connect net islands together. A net island is a set of
|
|
798
|
+
* ports that are connected to each other. If a there are multiple net islands
|
|
799
|
+
* that means that the net is not fully connected and we need to add traces
|
|
800
|
+
* such that the nets are fully connected
|
|
801
|
+
*/
|
|
802
|
+
doInitialPcbRouteNetIslands() {
|
|
980
803
|
const { db } = this.root;
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
};
|
|
991
|
-
|
|
992
|
-
// lib/components/base-components/NormalComponent.ts
|
|
993
|
-
import { symbols as symbols2 } from "schematic-symbols";
|
|
994
|
-
import { fp } from "footprinter";
|
|
995
|
-
import {
|
|
996
|
-
isValidElement as isReactElement2,
|
|
997
|
-
isValidElement
|
|
998
|
-
} from "react";
|
|
999
|
-
|
|
1000
|
-
// lib/fiber/create-instance-from-react-element.ts
|
|
1001
|
-
import ReactReconciler from "react-reconciler";
|
|
1002
|
-
|
|
1003
|
-
// lib/fiber/catalogue.ts
|
|
1004
|
-
var catalogue = {};
|
|
1005
|
-
var extendCatalogue = (objects) => {
|
|
1006
|
-
const altKeys = Object.fromEntries(
|
|
1007
|
-
Object.entries(objects).map(([key, v]) => [key.toLowerCase(), v])
|
|
1008
|
-
);
|
|
1009
|
-
Object.assign(catalogue, objects);
|
|
1010
|
-
Object.assign(catalogue, altKeys);
|
|
1011
|
-
};
|
|
1012
|
-
|
|
1013
|
-
// lib/fiber/create-instance-from-react-element.ts
|
|
1014
|
-
import { identity as identity2 } from "transformation-matrix";
|
|
1015
|
-
function prepare(object, state) {
|
|
1016
|
-
const instance = object;
|
|
1017
|
-
instance.__tsci = {
|
|
1018
|
-
...state
|
|
1019
|
-
};
|
|
1020
|
-
return object;
|
|
1021
|
-
}
|
|
1022
|
-
var hostConfig = {
|
|
1023
|
-
supportsMutation: true,
|
|
1024
|
-
createInstance(type, props) {
|
|
1025
|
-
const target = catalogue[type];
|
|
1026
|
-
if (!target) {
|
|
1027
|
-
if (Object.keys(catalogue).length === 0) {
|
|
1028
|
-
throw new Error(
|
|
1029
|
-
"No components registered in catalogue, did you forget to import lib/register-catalogue in your test file?"
|
|
1030
|
-
);
|
|
1031
|
-
}
|
|
1032
|
-
throw new Error(
|
|
1033
|
-
`Unsupported component type (not registered in @tscircuit/core catalogue): "${type}" See CREATING_NEW_COMPONENTS.md`
|
|
804
|
+
const { _parsedProps: props } = this;
|
|
805
|
+
const traces = this._getAllDirectlyConnectedTraces().filter(
|
|
806
|
+
(trace) => (trace._portsRoutedOnPcb?.length ?? 0) > 0
|
|
807
|
+
);
|
|
808
|
+
const islands = [];
|
|
809
|
+
for (const trace of traces) {
|
|
810
|
+
const tracePorts = trace._portsRoutedOnPcb;
|
|
811
|
+
const traceIsland = islands.find(
|
|
812
|
+
(island) => tracePorts.some((port) => island.ports.includes(port))
|
|
1034
813
|
);
|
|
814
|
+
if (!traceIsland) {
|
|
815
|
+
islands.push({ ports: [...tracePorts], traces: [trace] });
|
|
816
|
+
continue;
|
|
817
|
+
}
|
|
818
|
+
traceIsland.traces.push(trace);
|
|
819
|
+
traceIsland.ports.push(...tracePorts);
|
|
1035
820
|
}
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
},
|
|
1039
|
-
createTextInstance() {
|
|
1040
|
-
return {};
|
|
1041
|
-
},
|
|
1042
|
-
appendInitialChild(parentInstance, child) {
|
|
1043
|
-
parentInstance.add(child);
|
|
1044
|
-
},
|
|
1045
|
-
appendChild(parentInstance, child) {
|
|
1046
|
-
parentInstance.add(child);
|
|
1047
|
-
},
|
|
1048
|
-
appendChildToContainer(container, child) {
|
|
1049
|
-
container.add(child);
|
|
1050
|
-
},
|
|
1051
|
-
finalizeInitialChildren() {
|
|
1052
|
-
return false;
|
|
1053
|
-
},
|
|
1054
|
-
prepareUpdate() {
|
|
1055
|
-
return null;
|
|
1056
|
-
},
|
|
1057
|
-
shouldSetTextContent() {
|
|
1058
|
-
return false;
|
|
1059
|
-
},
|
|
1060
|
-
getRootHostContext() {
|
|
1061
|
-
return {};
|
|
1062
|
-
},
|
|
1063
|
-
getChildHostContext() {
|
|
1064
|
-
return {};
|
|
1065
|
-
},
|
|
1066
|
-
prepareForCommit() {
|
|
1067
|
-
return null;
|
|
1068
|
-
},
|
|
1069
|
-
resetAfterCommit() {
|
|
1070
|
-
},
|
|
1071
|
-
commitMount() {
|
|
1072
|
-
},
|
|
1073
|
-
commitUpdate() {
|
|
1074
|
-
},
|
|
1075
|
-
removeChild() {
|
|
1076
|
-
},
|
|
1077
|
-
clearContainer() {
|
|
1078
|
-
},
|
|
1079
|
-
supportsPersistence: false,
|
|
1080
|
-
getPublicInstance(instance) {
|
|
1081
|
-
return instance;
|
|
1082
|
-
},
|
|
1083
|
-
preparePortalMount(containerInfo) {
|
|
1084
|
-
throw new Error("Function not implemented.");
|
|
1085
|
-
},
|
|
1086
|
-
scheduleTimeout(fn, delay) {
|
|
1087
|
-
throw new Error("Function not implemented.");
|
|
1088
|
-
},
|
|
1089
|
-
cancelTimeout(id) {
|
|
1090
|
-
throw new Error("Function not implemented.");
|
|
1091
|
-
},
|
|
1092
|
-
noTimeout: void 0,
|
|
1093
|
-
isPrimaryRenderer: false,
|
|
1094
|
-
getCurrentEventPriority() {
|
|
1095
|
-
throw new Error("Function not implemented.");
|
|
1096
|
-
},
|
|
1097
|
-
getInstanceFromNode(node) {
|
|
1098
|
-
throw new Error("Function not implemented.");
|
|
1099
|
-
},
|
|
1100
|
-
beforeActiveInstanceBlur() {
|
|
1101
|
-
throw new Error("Function not implemented.");
|
|
1102
|
-
},
|
|
1103
|
-
afterActiveInstanceBlur() {
|
|
1104
|
-
throw new Error("Function not implemented.");
|
|
1105
|
-
},
|
|
1106
|
-
prepareScopeUpdate: (scopeInstance, instance) => {
|
|
1107
|
-
throw new Error("Function not implemented.");
|
|
1108
|
-
},
|
|
1109
|
-
getInstanceFromScope: (scopeInstance) => {
|
|
1110
|
-
throw new Error("Function not implemented.");
|
|
1111
|
-
},
|
|
1112
|
-
detachDeletedInstance: (node) => {
|
|
1113
|
-
throw new Error("Function not implemented.");
|
|
1114
|
-
},
|
|
1115
|
-
supportsHydration: false
|
|
1116
|
-
};
|
|
1117
|
-
var reconciler = ReactReconciler(hostConfig);
|
|
1118
|
-
var createInstanceFromReactElement = (reactElm) => {
|
|
1119
|
-
const rootContainer = {
|
|
1120
|
-
children: [],
|
|
1121
|
-
props: {
|
|
1122
|
-
name: "$root"
|
|
1123
|
-
},
|
|
1124
|
-
add(instance) {
|
|
1125
|
-
instance.parent = this;
|
|
1126
|
-
this.children.push(instance);
|
|
1127
|
-
},
|
|
1128
|
-
computePcbGlobalTransform() {
|
|
1129
|
-
return identity2();
|
|
821
|
+
if (islands.length === 0) {
|
|
822
|
+
return;
|
|
1130
823
|
}
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
824
|
+
const islandPairs = pairs(islands);
|
|
825
|
+
for (const [A, B] of islandPairs) {
|
|
826
|
+
const Apositions = A.ports.map(
|
|
827
|
+
(port) => port._getGlobalPcbPositionBeforeLayout()
|
|
828
|
+
);
|
|
829
|
+
const Bpositions = B.ports.map(
|
|
830
|
+
(port) => port._getGlobalPcbPositionBeforeLayout()
|
|
831
|
+
);
|
|
832
|
+
let closestDist = Infinity;
|
|
833
|
+
let closestPair = [-1, -1];
|
|
834
|
+
for (let i = 0; i < Apositions.length; i++) {
|
|
835
|
+
const Apos = Apositions[i];
|
|
836
|
+
for (let j = 0; j < Bpositions.length; j++) {
|
|
837
|
+
const Bpos = Bpositions[j];
|
|
838
|
+
const dist = Math.sqrt(
|
|
839
|
+
(Apos.x - Bpos.x) ** 2 + (Apos.y - Bpos.y) ** 2
|
|
840
|
+
);
|
|
841
|
+
if (dist < closestDist) {
|
|
842
|
+
closestDist = dist;
|
|
843
|
+
closestPair = [i, j];
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
const Aport = A.ports[closestPair[0]];
|
|
848
|
+
const Bport = B.ports[closestPair[1]];
|
|
849
|
+
const pcbElements = db.toArray().filter(
|
|
850
|
+
(elm) => elm.type === "pcb_smtpad" || elm.type === "pcb_trace" || elm.type === "pcb_plated_hole" || elm.type === "pcb_hole" || elm.type === "source_port" || elm.type === "pcb_port"
|
|
851
|
+
);
|
|
852
|
+
const { solution } = autoroute(
|
|
853
|
+
pcbElements.concat([
|
|
854
|
+
{
|
|
855
|
+
type: "source_trace",
|
|
856
|
+
source_trace_id: "__net_trace_tmp",
|
|
857
|
+
connected_source_port_ids: [
|
|
858
|
+
Aport.source_port_id,
|
|
859
|
+
Bport.source_port_id
|
|
860
|
+
]
|
|
861
|
+
}
|
|
862
|
+
])
|
|
863
|
+
// Remove as any when autorouting-dataset has been updated
|
|
864
|
+
);
|
|
865
|
+
const trace = solution[0];
|
|
866
|
+
if (!trace) {
|
|
867
|
+
this.renderError("Failed to route net islands");
|
|
868
|
+
return;
|
|
869
|
+
}
|
|
870
|
+
db.pcb_trace.insert(trace);
|
|
871
|
+
}
|
|
872
|
+
}
|
|
1155
873
|
};
|
|
1156
874
|
|
|
1157
|
-
// lib/utils/
|
|
1158
|
-
|
|
1159
|
-
const
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
}
|
|
875
|
+
// lib/utils/components/createNetsFromProps.ts
|
|
876
|
+
var createNetsFromProps = (component, props) => {
|
|
877
|
+
for (const prop of props) {
|
|
878
|
+
if (typeof prop === "string" && prop.startsWith("net.")) {
|
|
879
|
+
if (!component.getSubcircuit().selectOne(prop)) {
|
|
880
|
+
component.getSubcircuit().add(new Net({ name: prop.split("net.")[1] }));
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
};
|
|
1166
885
|
|
|
1167
886
|
// lib/components/primitive-components/SmtPad.ts
|
|
1168
887
|
import { smtPadProps } from "@tscircuit/props";
|
|
@@ -1233,6 +952,16 @@ var SmtPad = class extends PrimitiveComponent {
|
|
|
1233
952
|
x: position.x,
|
|
1234
953
|
y: position.y
|
|
1235
954
|
});
|
|
955
|
+
db.pcb_solder_paste.insert({
|
|
956
|
+
layer: pcb_smtpad.layer,
|
|
957
|
+
shape: "circle",
|
|
958
|
+
// @ts-ignore: no idea why this is triggering
|
|
959
|
+
radius: pcb_smtpad.radius * 0.7,
|
|
960
|
+
x: pcb_smtpad.x,
|
|
961
|
+
y: pcb_smtpad.y,
|
|
962
|
+
pcb_component_id: pcb_smtpad.pcb_component_id,
|
|
963
|
+
pcb_smtpad_id: pcb_smtpad.pcb_smtpad_id
|
|
964
|
+
});
|
|
1236
965
|
} else if (props.shape === "rect") {
|
|
1237
966
|
pcb_smtpad = db.pcb_smtpad.insert({
|
|
1238
967
|
pcb_component_id,
|
|
@@ -1245,6 +974,18 @@ var SmtPad = class extends PrimitiveComponent {
|
|
|
1245
974
|
x: position.x,
|
|
1246
975
|
y: position.y
|
|
1247
976
|
});
|
|
977
|
+
if (pcb_smtpad.shape === "rect")
|
|
978
|
+
db.pcb_solder_paste.insert({
|
|
979
|
+
layer: pcb_smtpad.layer,
|
|
980
|
+
shape: "rect",
|
|
981
|
+
// @ts-ignore: no idea why this is triggering
|
|
982
|
+
width: pcb_smtpad.width * 0.7,
|
|
983
|
+
height: pcb_smtpad.height * 0.7,
|
|
984
|
+
x: pcb_smtpad.x,
|
|
985
|
+
y: pcb_smtpad.y,
|
|
986
|
+
pcb_component_id: pcb_smtpad.pcb_component_id,
|
|
987
|
+
pcb_smtpad_id: pcb_smtpad.pcb_smtpad_id
|
|
988
|
+
});
|
|
1248
989
|
}
|
|
1249
990
|
if (pcb_smtpad) {
|
|
1250
991
|
this.pcb_smtpad_id = pcb_smtpad.pcb_smtpad_id;
|
|
@@ -1301,7 +1042,7 @@ var SmtPad = class extends PrimitiveComponent {
|
|
|
1301
1042
|
|
|
1302
1043
|
// lib/components/primitive-components/SilkscreenPath.ts
|
|
1303
1044
|
import { silkscreenPathProps } from "@tscircuit/props";
|
|
1304
|
-
import { applyToPoint as
|
|
1045
|
+
import { applyToPoint as applyToPoint3 } from "transformation-matrix";
|
|
1305
1046
|
var SilkscreenPath = class extends PrimitiveComponent {
|
|
1306
1047
|
pcb_silkscreen_path_id = null;
|
|
1307
1048
|
get config() {
|
|
@@ -1324,7 +1065,7 @@ var SilkscreenPath = class extends PrimitiveComponent {
|
|
|
1324
1065
|
pcb_component_id: this.parent?.pcb_component_id,
|
|
1325
1066
|
layer,
|
|
1326
1067
|
route: props.route.map((p) => {
|
|
1327
|
-
const transformedPosition =
|
|
1068
|
+
const transformedPosition = applyToPoint3(transform, {
|
|
1328
1069
|
x: p.x,
|
|
1329
1070
|
y: p.y
|
|
1330
1071
|
});
|
|
@@ -1512,250 +1253,527 @@ var createComponentsFromSoup = (soup) => {
|
|
|
1512
1253
|
portHints: elm.port_hints
|
|
1513
1254
|
})
|
|
1514
1255
|
);
|
|
1515
|
-
} else if (elm.type === "pcb_silkscreen_path") {
|
|
1516
|
-
components.push(
|
|
1517
|
-
new SilkscreenPath({
|
|
1518
|
-
layer: elm.layer,
|
|
1519
|
-
route: elm.route,
|
|
1520
|
-
strokeWidth: elm.stroke_width
|
|
1521
|
-
})
|
|
1256
|
+
} else if (elm.type === "pcb_silkscreen_path") {
|
|
1257
|
+
components.push(
|
|
1258
|
+
new SilkscreenPath({
|
|
1259
|
+
layer: elm.layer,
|
|
1260
|
+
route: elm.route,
|
|
1261
|
+
strokeWidth: elm.stroke_width
|
|
1262
|
+
})
|
|
1263
|
+
);
|
|
1264
|
+
} else if (elm.type === "pcb_plated_hole" && elm.shape === "circle") {
|
|
1265
|
+
if (elm.shape === "circle") {
|
|
1266
|
+
components.push(
|
|
1267
|
+
new PlatedHole({
|
|
1268
|
+
pcbX: elm.x,
|
|
1269
|
+
pcbY: elm.y,
|
|
1270
|
+
shape: "circle",
|
|
1271
|
+
holeDiameter: elm.hole_diameter,
|
|
1272
|
+
outerDiameter: elm.outer_diameter,
|
|
1273
|
+
portHints: elm.port_hints
|
|
1274
|
+
})
|
|
1275
|
+
);
|
|
1276
|
+
}
|
|
1277
|
+
} else if (elm.type === "pcb_keepout" && elm.shape === "circle") {
|
|
1278
|
+
components.push(
|
|
1279
|
+
new Keepout({
|
|
1280
|
+
pcbX: elm.center.x,
|
|
1281
|
+
pcbY: elm.center.y,
|
|
1282
|
+
shape: "circle",
|
|
1283
|
+
radius: elm.radius
|
|
1284
|
+
})
|
|
1285
|
+
);
|
|
1286
|
+
} else if (elm.type === "pcb_keepout" && elm.shape === "rect") {
|
|
1287
|
+
components.push(
|
|
1288
|
+
new Keepout({
|
|
1289
|
+
pcbX: elm.center.x,
|
|
1290
|
+
pcbY: elm.center.y,
|
|
1291
|
+
shape: "rect",
|
|
1292
|
+
width: elm.width,
|
|
1293
|
+
height: elm.height
|
|
1294
|
+
})
|
|
1295
|
+
);
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
return components;
|
|
1299
|
+
};
|
|
1300
|
+
|
|
1301
|
+
// lib/utils/get-bounds-of-pcb-components.ts
|
|
1302
|
+
function getBoundsOfPcbComponents(components) {
|
|
1303
|
+
let minX = Infinity;
|
|
1304
|
+
let minY = Infinity;
|
|
1305
|
+
let maxX = -Infinity;
|
|
1306
|
+
let maxY = -Infinity;
|
|
1307
|
+
for (const child of components) {
|
|
1308
|
+
if (child.isPcbPrimitive) {
|
|
1309
|
+
const { x, y } = child._getGlobalPcbPositionBeforeLayout();
|
|
1310
|
+
const { width: width2, height: height2 } = child.getPcbSize();
|
|
1311
|
+
minX = Math.min(minX, x - width2 / 2);
|
|
1312
|
+
minY = Math.min(minY, y - height2 / 2);
|
|
1313
|
+
maxX = Math.max(maxX, x + width2 / 2);
|
|
1314
|
+
maxY = Math.max(maxY, y + height2 / 2);
|
|
1315
|
+
} else if (child.componentName === "Footprint") {
|
|
1316
|
+
const childBounds = getBoundsOfPcbComponents(child.children);
|
|
1317
|
+
minX = Math.min(minX, childBounds.minX);
|
|
1318
|
+
minY = Math.min(minY, childBounds.minY);
|
|
1319
|
+
maxX = Math.max(maxX, childBounds.maxX);
|
|
1320
|
+
maxY = Math.max(maxY, childBounds.maxY);
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1323
|
+
let width = maxX - minX;
|
|
1324
|
+
let height = maxY - minY;
|
|
1325
|
+
if (width < 0) width = 0;
|
|
1326
|
+
if (height < 0) height = 0;
|
|
1327
|
+
return {
|
|
1328
|
+
minX,
|
|
1329
|
+
minY,
|
|
1330
|
+
maxX,
|
|
1331
|
+
maxY,
|
|
1332
|
+
width,
|
|
1333
|
+
height
|
|
1334
|
+
};
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1337
|
+
// lib/utils/get-relative-direction.ts
|
|
1338
|
+
function getRelativeDirection(pointA, pointB) {
|
|
1339
|
+
const dx = pointB.x - pointA.x;
|
|
1340
|
+
const dy = pointB.y - pointA.y;
|
|
1341
|
+
if (Math.abs(dx) > Math.abs(dy)) {
|
|
1342
|
+
return dx > 0 ? "right" : "left";
|
|
1343
|
+
}
|
|
1344
|
+
return dy > 0 ? "down" : "up";
|
|
1345
|
+
}
|
|
1346
|
+
|
|
1347
|
+
// lib/components/primitive-components/Port.ts
|
|
1348
|
+
import "schematic-symbols";
|
|
1349
|
+
import { applyToPoint as applyToPoint4, compose as compose3, translate as translate3 } from "transformation-matrix";
|
|
1350
|
+
import { z as z3 } from "zod";
|
|
1351
|
+
var portProps = z3.object({
|
|
1352
|
+
name: z3.string().optional(),
|
|
1353
|
+
pinNumber: z3.number().optional(),
|
|
1354
|
+
aliases: z3.array(z3.string()).optional()
|
|
1355
|
+
});
|
|
1356
|
+
var Port = class extends PrimitiveComponent {
|
|
1357
|
+
source_port_id = null;
|
|
1358
|
+
pcb_port_id = null;
|
|
1359
|
+
schematic_port_id = null;
|
|
1360
|
+
schematicSymbolPortDef = null;
|
|
1361
|
+
matchedComponents;
|
|
1362
|
+
facingDirection = null;
|
|
1363
|
+
get config() {
|
|
1364
|
+
return {
|
|
1365
|
+
componentName: "Port",
|
|
1366
|
+
zodProps: portProps
|
|
1367
|
+
};
|
|
1368
|
+
}
|
|
1369
|
+
constructor(props) {
|
|
1370
|
+
if (!props.name && props.pinNumber) props.name = `pin${props.pinNumber}`;
|
|
1371
|
+
if (!props.name) {
|
|
1372
|
+
throw new Error("Port must have a name or a pinNumber");
|
|
1373
|
+
}
|
|
1374
|
+
super(props);
|
|
1375
|
+
this.matchedComponents = [];
|
|
1376
|
+
}
|
|
1377
|
+
_getGlobalPcbPositionBeforeLayout() {
|
|
1378
|
+
const matchedPcbElm = this.matchedComponents.find((c) => c.isPcbPrimitive);
|
|
1379
|
+
if (!matchedPcbElm) {
|
|
1380
|
+
throw new Error(
|
|
1381
|
+
`Port ${this} has no matched pcb component, can't get global schematic position`
|
|
1382
|
+
);
|
|
1383
|
+
}
|
|
1384
|
+
return matchedPcbElm?._getGlobalPcbPositionBeforeLayout() ?? { x: 0, y: 0 };
|
|
1385
|
+
}
|
|
1386
|
+
_getPcbCircuitJsonBounds() {
|
|
1387
|
+
if (!this.pcb_port_id) {
|
|
1388
|
+
return super._getPcbCircuitJsonBounds();
|
|
1389
|
+
}
|
|
1390
|
+
const { db } = this.root;
|
|
1391
|
+
const pcb_port = db.pcb_port.get(this.pcb_port_id);
|
|
1392
|
+
return {
|
|
1393
|
+
center: { x: pcb_port.x, y: pcb_port.y },
|
|
1394
|
+
bounds: { left: 0, top: 0, right: 0, bottom: 0 },
|
|
1395
|
+
width: 0,
|
|
1396
|
+
height: 0
|
|
1397
|
+
};
|
|
1398
|
+
}
|
|
1399
|
+
_getGlobalPcbPositionAfterLayout() {
|
|
1400
|
+
return this._getPcbCircuitJsonBounds().center;
|
|
1401
|
+
}
|
|
1402
|
+
_getGlobalSchematicPositionBeforeLayout() {
|
|
1403
|
+
if (!this.schematicSymbolPortDef) {
|
|
1404
|
+
return applyToPoint4(this.parent.computeSchematicGlobalTransform(), {
|
|
1405
|
+
x: 0,
|
|
1406
|
+
y: 0
|
|
1407
|
+
});
|
|
1408
|
+
}
|
|
1409
|
+
const symbol = this.parent?.getSchematicSymbol();
|
|
1410
|
+
if (!symbol) {
|
|
1411
|
+
console.warn(`Could not find parent symbol for ${this}`);
|
|
1412
|
+
return { x: 0, y: 0 };
|
|
1413
|
+
}
|
|
1414
|
+
const transform = compose3(
|
|
1415
|
+
this.parent.computeSchematicGlobalTransform(),
|
|
1416
|
+
translate3(-symbol.center.x, -symbol.center.y)
|
|
1417
|
+
);
|
|
1418
|
+
return applyToPoint4(transform, this.schematicSymbolPortDef);
|
|
1419
|
+
}
|
|
1420
|
+
/**
|
|
1421
|
+
* Smtpads and platedholes call this method to register themselves as a match
|
|
1422
|
+
* for this port. All the matching is done by primitives other than the Port,
|
|
1423
|
+
* but everyone registers themselves as a match with their Port.
|
|
1424
|
+
*/
|
|
1425
|
+
registerMatch(component) {
|
|
1426
|
+
this.matchedComponents.push(component);
|
|
1427
|
+
}
|
|
1428
|
+
getNameAndAliases() {
|
|
1429
|
+
const { _parsedProps: props } = this;
|
|
1430
|
+
return Array.from(
|
|
1431
|
+
/* @__PURE__ */ new Set([
|
|
1432
|
+
...props.aliases ?? [],
|
|
1433
|
+
props.name,
|
|
1434
|
+
...typeof props.pinNumber === "number" ? [`pin${props.pinNumber}`, props.pinNumber.toString()] : [],
|
|
1435
|
+
...this.externallyAddedAliases
|
|
1436
|
+
])
|
|
1437
|
+
);
|
|
1438
|
+
}
|
|
1439
|
+
isMatchingPort(port) {
|
|
1440
|
+
return this.isMatchingAnyOf(port.getNameAndAliases());
|
|
1441
|
+
}
|
|
1442
|
+
getPortSelector() {
|
|
1443
|
+
return `.${this.parent?.props.name} > port.${this.props.name}`;
|
|
1444
|
+
}
|
|
1445
|
+
getAvailablePcbLayers() {
|
|
1446
|
+
return Array.from(
|
|
1447
|
+
new Set(this.matchedComponents.flatMap((c) => c.getAvailablePcbLayers()))
|
|
1448
|
+
);
|
|
1449
|
+
}
|
|
1450
|
+
/**
|
|
1451
|
+
* Return traces that are explicitly connected to this port (not via a net)
|
|
1452
|
+
*/
|
|
1453
|
+
_getDirectlyConnectedTraces() {
|
|
1454
|
+
const allSubcircuitTraces = this.getSubcircuit().selectAll(
|
|
1455
|
+
"trace"
|
|
1456
|
+
);
|
|
1457
|
+
const connectedTraces = allSubcircuitTraces.filter(
|
|
1458
|
+
(trace) => trace._isExplicitlyConnectedToPort(this)
|
|
1459
|
+
);
|
|
1460
|
+
return connectedTraces;
|
|
1461
|
+
}
|
|
1462
|
+
doInitialSourceRender() {
|
|
1463
|
+
const { db } = this.root;
|
|
1464
|
+
const { _parsedProps: props } = this;
|
|
1465
|
+
const port_hints = this.getNameAndAliases();
|
|
1466
|
+
const source_port = db.source_port.insert({
|
|
1467
|
+
name: props.name,
|
|
1468
|
+
pin_number: props.pinNumber,
|
|
1469
|
+
port_hints,
|
|
1470
|
+
source_component_id: this.parent?.source_component_id
|
|
1471
|
+
});
|
|
1472
|
+
this.source_port_id = source_port.source_port_id;
|
|
1473
|
+
}
|
|
1474
|
+
doInitialSourceParentAttachment() {
|
|
1475
|
+
const { db } = this.root;
|
|
1476
|
+
if (!this.parent?.source_component_id) {
|
|
1477
|
+
throw new Error(
|
|
1478
|
+
`${this.getString()} has no parent source component (parent: ${this.parent?.getString()})`
|
|
1479
|
+
);
|
|
1480
|
+
}
|
|
1481
|
+
db.source_port.update(this.source_port_id, {
|
|
1482
|
+
source_component_id: this.parent?.source_component_id
|
|
1483
|
+
});
|
|
1484
|
+
this.source_component_id = this.parent?.source_component_id;
|
|
1485
|
+
}
|
|
1486
|
+
doInitialPcbPortRender() {
|
|
1487
|
+
const { db } = this.root;
|
|
1488
|
+
const { matchedComponents } = this;
|
|
1489
|
+
if (!this.parent?.pcb_component_id) {
|
|
1490
|
+
throw new Error(
|
|
1491
|
+
`${this.getString()} has no parent pcb component, cannot render pcb_port (parent: ${this.parent?.getString()})`
|
|
1522
1492
|
);
|
|
1523
|
-
}
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
shape: "circle",
|
|
1530
|
-
holeDiameter: elm.hole_diameter,
|
|
1531
|
-
outerDiameter: elm.outer_diameter,
|
|
1532
|
-
portHints: elm.port_hints
|
|
1533
|
-
})
|
|
1534
|
-
);
|
|
1535
|
-
}
|
|
1536
|
-
} else if (elm.type === "pcb_keepout" && elm.shape === "circle") {
|
|
1537
|
-
components.push(
|
|
1538
|
-
new Keepout({
|
|
1539
|
-
pcbX: elm.center.x,
|
|
1540
|
-
pcbY: elm.center.y,
|
|
1541
|
-
shape: "circle",
|
|
1542
|
-
radius: elm.radius
|
|
1543
|
-
})
|
|
1493
|
+
}
|
|
1494
|
+
const pcbMatches = matchedComponents.filter((c) => c.isPcbPrimitive);
|
|
1495
|
+
if (pcbMatches.length === 0) return;
|
|
1496
|
+
if (pcbMatches.length > 1) {
|
|
1497
|
+
throw new Error(
|
|
1498
|
+
`${this.getString()} has multiple pcb matches, unclear how to place pcb_port: ${pcbMatches.map((c) => c.getString()).join(", ")}`
|
|
1544
1499
|
);
|
|
1545
|
-
}
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1500
|
+
}
|
|
1501
|
+
const pcbMatch = pcbMatches[0];
|
|
1502
|
+
if ("_getPcbCircuitJsonBounds" in pcbMatch) {
|
|
1503
|
+
const pcb_port = db.pcb_port.insert({
|
|
1504
|
+
pcb_component_id: this.parent?.pcb_component_id,
|
|
1505
|
+
layers: this.getAvailablePcbLayers(),
|
|
1506
|
+
...pcbMatch._getPcbCircuitJsonBounds().center,
|
|
1507
|
+
source_port_id: this.source_port_id
|
|
1508
|
+
});
|
|
1509
|
+
this.pcb_port_id = pcb_port.pcb_port_id;
|
|
1510
|
+
} else {
|
|
1511
|
+
throw new Error(
|
|
1512
|
+
`${pcbMatch.getString()} does not have a _getGlobalPcbPositionBeforeLayout method (needed for pcb_port placement)`
|
|
1554
1513
|
);
|
|
1555
1514
|
}
|
|
1556
1515
|
}
|
|
1557
|
-
|
|
1516
|
+
doInitialSchematicPortRender() {
|
|
1517
|
+
const { db } = this.root;
|
|
1518
|
+
const { _parsedProps: props } = this;
|
|
1519
|
+
const container = this.getPrimitiveContainer();
|
|
1520
|
+
if (!container) return;
|
|
1521
|
+
let center = this._getGlobalSchematicPositionBeforeLayout();
|
|
1522
|
+
if ("schematicDimensions" in container && props.pinNumber !== void 0) {
|
|
1523
|
+
const chipDims = container.schematicDimensions;
|
|
1524
|
+
center = chipDims.getPortPositionByPinNumber(props.pinNumber);
|
|
1525
|
+
}
|
|
1526
|
+
const containerCenter = container._getGlobalSchematicPositionBeforeLayout();
|
|
1527
|
+
this.facingDirection = getRelativeDirection(containerCenter, center);
|
|
1528
|
+
const schematic_port = db.schematic_port.insert({
|
|
1529
|
+
schematic_component_id: this.parent?.schematic_component_id,
|
|
1530
|
+
center,
|
|
1531
|
+
source_port_id: this.source_port_id,
|
|
1532
|
+
facing_direction: this.facingDirection
|
|
1533
|
+
});
|
|
1534
|
+
this.schematic_port_id = schematic_port.schematic_port_id;
|
|
1535
|
+
}
|
|
1536
|
+
_setPositionFromLayout(newCenter) {
|
|
1537
|
+
const { db } = this.root;
|
|
1538
|
+
if (!this.pcb_port_id) return;
|
|
1539
|
+
db.pcb_port.update(this.pcb_port_id, {
|
|
1540
|
+
x: newCenter.x,
|
|
1541
|
+
y: newCenter.y
|
|
1542
|
+
});
|
|
1543
|
+
}
|
|
1544
|
+
_hasMatchedPcbPrimitive() {
|
|
1545
|
+
return this.matchedComponents.some((c) => c.isPcbPrimitive);
|
|
1546
|
+
}
|
|
1558
1547
|
};
|
|
1559
1548
|
|
|
1560
|
-
// lib/
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
}
|
|
1569
|
-
return result;
|
|
1549
|
+
// lib/utils/getPortFromHints.ts
|
|
1550
|
+
function getPortFromHints(hints) {
|
|
1551
|
+
const pinNumber = hints.find((p) => /^(pin)?\d+$/.test(p));
|
|
1552
|
+
if (!pinNumber) return null;
|
|
1553
|
+
return new Port({
|
|
1554
|
+
pinNumber: Number.parseInt(pinNumber.replace(/^pin/, "")),
|
|
1555
|
+
aliases: hints.filter((p) => p !== pinNumber)
|
|
1556
|
+
});
|
|
1570
1557
|
}
|
|
1571
1558
|
|
|
1572
|
-
// lib/components/
|
|
1573
|
-
import {
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
}
|
|
1577
|
-
|
|
1578
|
-
|
|
1559
|
+
// lib/components/base-components/NormalComponent.ts
|
|
1560
|
+
import {
|
|
1561
|
+
isValidElement as isReactElement2,
|
|
1562
|
+
isValidElement
|
|
1563
|
+
} from "react";
|
|
1564
|
+
import { symbols as symbols2 } from "schematic-symbols";
|
|
1565
|
+
import { z as z4 } from "zod";
|
|
1566
|
+
|
|
1567
|
+
// lib/components/primitive-components/Footprint.ts
|
|
1568
|
+
import { footprintProps } from "@tscircuit/props";
|
|
1569
|
+
import * as kiwi from "@lume/kiwi";
|
|
1570
|
+
import Debug from "debug";
|
|
1571
|
+
var debug = Debug("tscircuit:core:footprint");
|
|
1572
|
+
var Footprint = class extends PrimitiveComponent {
|
|
1579
1573
|
get config() {
|
|
1580
1574
|
return {
|
|
1581
|
-
componentName: "
|
|
1582
|
-
zodProps:
|
|
1575
|
+
componentName: "Footprint",
|
|
1576
|
+
zodProps: footprintProps
|
|
1583
1577
|
};
|
|
1584
1578
|
}
|
|
1585
|
-
getPortSelector() {
|
|
1586
|
-
return `net.${this.props.name}`;
|
|
1587
|
-
}
|
|
1588
|
-
doInitialSourceRender() {
|
|
1589
|
-
const { db } = this.root;
|
|
1590
|
-
const { _parsedProps: props } = this;
|
|
1591
|
-
const net = db.source_net.insert({
|
|
1592
|
-
name: props.name,
|
|
1593
|
-
member_source_group_ids: []
|
|
1594
|
-
});
|
|
1595
|
-
this.source_net_id = net.source_net_id;
|
|
1596
|
-
}
|
|
1597
1579
|
/**
|
|
1598
|
-
*
|
|
1599
|
-
*
|
|
1600
|
-
* TODO currently we're not checking for indirect connections (traces that are
|
|
1601
|
-
* connected to other traces that are in turn connected to the net)
|
|
1580
|
+
* A footprint is a constrainedlayout, the db elements are adjusted according
|
|
1581
|
+
* to any constraints that are defined.
|
|
1602
1582
|
*/
|
|
1603
|
-
|
|
1604
|
-
const
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1583
|
+
doInitialPcbFootprintLayout() {
|
|
1584
|
+
const constraints = this.children.filter(
|
|
1585
|
+
(child) => child.componentName === "Constraint"
|
|
1586
|
+
);
|
|
1587
|
+
if (constraints.length === 0) return;
|
|
1588
|
+
const { isFlipped } = this._getPcbPrimitiveFlippedHelpers();
|
|
1589
|
+
const maybeFlipLeftRight = (props) => {
|
|
1590
|
+
if (isFlipped) {
|
|
1591
|
+
if ("left" in props && "right" in props) {
|
|
1592
|
+
return {
|
|
1593
|
+
...props,
|
|
1594
|
+
left: props.right,
|
|
1595
|
+
right: props.left
|
|
1596
|
+
};
|
|
1612
1597
|
}
|
|
1613
1598
|
}
|
|
1599
|
+
return props;
|
|
1600
|
+
};
|
|
1601
|
+
const involvedComponents = constraints.flatMap(
|
|
1602
|
+
(constraint) => constraint._getAllReferencedComponents().componentsWithSelectors
|
|
1603
|
+
).map(({ component, selector, componentSelector, edge }) => ({
|
|
1604
|
+
component,
|
|
1605
|
+
selector,
|
|
1606
|
+
componentSelector,
|
|
1607
|
+
edge,
|
|
1608
|
+
bounds: component._getPcbCircuitJsonBounds()
|
|
1609
|
+
}));
|
|
1610
|
+
if (involvedComponents.some((c) => c.edge)) {
|
|
1611
|
+
throw new Error(
|
|
1612
|
+
"edge constraints not implemented yet for footprint layout, contributions welcome!"
|
|
1613
|
+
);
|
|
1614
1614
|
}
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
/**
|
|
1618
|
-
* Get all traces that are directly connected to this net, i.e. they list
|
|
1619
|
-
* this net in their path, from, or to props
|
|
1620
|
-
*/
|
|
1621
|
-
_getAllDirectlyConnectedTraces() {
|
|
1622
|
-
const allTraces = this.getSubcircuit().selectAll("trace");
|
|
1623
|
-
const connectedTraces = [];
|
|
1624
|
-
for (const trace of allTraces) {
|
|
1625
|
-
if (trace._isExplicitlyConnectedToNet(this)) {
|
|
1626
|
-
connectedTraces.push(trace);
|
|
1627
|
-
}
|
|
1615
|
+
function getComponentDetails(selector) {
|
|
1616
|
+
return involvedComponents.find(({ selector: s }) => s === selector);
|
|
1628
1617
|
}
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
* such that the nets are fully connected
|
|
1636
|
-
*/
|
|
1637
|
-
doInitialPcbRouteNetIslands() {
|
|
1638
|
-
const { db } = this.root;
|
|
1639
|
-
const { _parsedProps: props } = this;
|
|
1640
|
-
const traces = this._getAllDirectlyConnectedTraces().filter(
|
|
1641
|
-
(trace) => (trace._portsRoutedOnPcb?.length ?? 0) > 0
|
|
1642
|
-
);
|
|
1643
|
-
const islands = [];
|
|
1644
|
-
for (const trace of traces) {
|
|
1645
|
-
const tracePorts = trace._portsRoutedOnPcb;
|
|
1646
|
-
const traceIsland = islands.find(
|
|
1647
|
-
(island) => tracePorts.some((port) => island.ports.includes(port))
|
|
1648
|
-
);
|
|
1649
|
-
if (!traceIsland) {
|
|
1650
|
-
islands.push({ ports: [...tracePorts], traces: [trace] });
|
|
1651
|
-
continue;
|
|
1618
|
+
const solver = new kiwi.Solver();
|
|
1619
|
+
const kVars = {};
|
|
1620
|
+
function getKVar(name) {
|
|
1621
|
+
if (!(name in kVars)) {
|
|
1622
|
+
kVars[name] = new kiwi.Variable(name);
|
|
1623
|
+
solver.addEditVariable(kVars[name], kiwi.Strength.weak);
|
|
1652
1624
|
}
|
|
1653
|
-
|
|
1654
|
-
traceIsland.ports.push(...tracePorts);
|
|
1625
|
+
return kVars[name];
|
|
1655
1626
|
}
|
|
1656
|
-
|
|
1657
|
-
|
|
1627
|
+
for (const { selector, bounds: bounds2 } of involvedComponents) {
|
|
1628
|
+
const kvx = getKVar(`${selector}_x`);
|
|
1629
|
+
const kvy = getKVar(`${selector}_y`);
|
|
1630
|
+
solver.suggestValue(kvx, bounds2.center.x);
|
|
1631
|
+
solver.suggestValue(kvy, bounds2.center.y);
|
|
1658
1632
|
}
|
|
1659
|
-
const
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1633
|
+
for (const constraint of constraints) {
|
|
1634
|
+
const props = constraint._parsedProps;
|
|
1635
|
+
if ("xDist" in props) {
|
|
1636
|
+
const { xDist, left, right, edgeToEdge, centerToCenter } = maybeFlipLeftRight(props);
|
|
1637
|
+
const leftVar = getKVar(`${left}_x`);
|
|
1638
|
+
const rightVar = getKVar(`${right}_x`);
|
|
1639
|
+
const leftBounds = getComponentDetails(left)?.bounds;
|
|
1640
|
+
const rightBounds = getComponentDetails(right)?.bounds;
|
|
1641
|
+
if (centerToCenter) {
|
|
1642
|
+
const expr = new kiwi.Expression(rightVar, [-1, leftVar]);
|
|
1643
|
+
solver.addConstraint(
|
|
1644
|
+
new kiwi.Constraint(
|
|
1645
|
+
expr,
|
|
1646
|
+
kiwi.Operator.Eq,
|
|
1647
|
+
props.xDist,
|
|
1648
|
+
kiwi.Strength.required
|
|
1649
|
+
)
|
|
1650
|
+
);
|
|
1651
|
+
} else if (edgeToEdge) {
|
|
1652
|
+
const expr = new kiwi.Expression(
|
|
1653
|
+
rightVar,
|
|
1654
|
+
-rightBounds.width / 2,
|
|
1655
|
+
[-1, leftVar],
|
|
1656
|
+
-leftBounds.width / 2
|
|
1657
|
+
);
|
|
1658
|
+
solver.addConstraint(
|
|
1659
|
+
new kiwi.Constraint(
|
|
1660
|
+
expr,
|
|
1661
|
+
kiwi.Operator.Eq,
|
|
1662
|
+
props.xDist,
|
|
1663
|
+
kiwi.Strength.required
|
|
1664
|
+
)
|
|
1665
|
+
);
|
|
1666
|
+
}
|
|
1667
|
+
} else if ("yDist" in props) {
|
|
1668
|
+
const { yDist, top, bottom, edgeToEdge, centerToCenter } = props;
|
|
1669
|
+
const topVar = getKVar(`${top}_y`);
|
|
1670
|
+
const bottomVar = getKVar(`${bottom}_y`);
|
|
1671
|
+
const topBounds = getComponentDetails(top)?.bounds;
|
|
1672
|
+
const bottomBounds = getComponentDetails(bottom)?.bounds;
|
|
1673
|
+
if (centerToCenter) {
|
|
1674
|
+
const expr = new kiwi.Expression(topVar, [-1, bottomVar]);
|
|
1675
|
+
solver.addConstraint(
|
|
1676
|
+
new kiwi.Constraint(
|
|
1677
|
+
expr,
|
|
1678
|
+
kiwi.Operator.Eq,
|
|
1679
|
+
props.yDist,
|
|
1680
|
+
kiwi.Strength.required
|
|
1681
|
+
)
|
|
1682
|
+
);
|
|
1683
|
+
} else if (edgeToEdge) {
|
|
1684
|
+
const expr = new kiwi.Expression(
|
|
1685
|
+
topVar,
|
|
1686
|
+
topBounds.height / 2,
|
|
1687
|
+
[-1, bottomVar],
|
|
1688
|
+
-bottomBounds.height / 2
|
|
1689
|
+
);
|
|
1690
|
+
solver.addConstraint(
|
|
1691
|
+
new kiwi.Constraint(
|
|
1692
|
+
expr,
|
|
1693
|
+
kiwi.Operator.Eq,
|
|
1694
|
+
props.yDist,
|
|
1695
|
+
kiwi.Strength.required
|
|
1696
|
+
)
|
|
1675
1697
|
);
|
|
1676
|
-
if (dist < closestDist) {
|
|
1677
|
-
closestDist = dist;
|
|
1678
|
-
closestPair = [i, j];
|
|
1679
|
-
}
|
|
1680
1698
|
}
|
|
1699
|
+
} else if ("sameY" in props) {
|
|
1700
|
+
const { for: selectors } = props;
|
|
1701
|
+
if (selectors.length < 2) continue;
|
|
1702
|
+
const vars = selectors.map((selector) => getKVar(`${selector}_y`));
|
|
1703
|
+
const expr = new kiwi.Expression(...vars.slice(1));
|
|
1704
|
+
solver.addConstraint(
|
|
1705
|
+
new kiwi.Constraint(
|
|
1706
|
+
expr,
|
|
1707
|
+
kiwi.Operator.Eq,
|
|
1708
|
+
vars[0],
|
|
1709
|
+
kiwi.Strength.required
|
|
1710
|
+
)
|
|
1711
|
+
);
|
|
1712
|
+
} else if ("sameX" in props) {
|
|
1713
|
+
const { for: selectors } = props;
|
|
1714
|
+
if (selectors.length < 2) continue;
|
|
1715
|
+
const vars = selectors.map((selector) => getKVar(`${selector}_x`));
|
|
1716
|
+
const expr = new kiwi.Expression(...vars.slice(1));
|
|
1717
|
+
solver.addConstraint(
|
|
1718
|
+
new kiwi.Constraint(
|
|
1719
|
+
expr,
|
|
1720
|
+
kiwi.Operator.Eq,
|
|
1721
|
+
vars[0],
|
|
1722
|
+
kiwi.Strength.required
|
|
1723
|
+
)
|
|
1724
|
+
);
|
|
1681
1725
|
}
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
source_trace_id: "__net_trace_tmp",
|
|
1692
|
-
connected_source_port_ids: [
|
|
1693
|
-
Aport.source_port_id,
|
|
1694
|
-
Bport.source_port_id
|
|
1695
|
-
]
|
|
1696
|
-
}
|
|
1697
|
-
])
|
|
1698
|
-
// Remove as any when autorouting-dataset has been updated
|
|
1726
|
+
}
|
|
1727
|
+
solver.updateVariables();
|
|
1728
|
+
if (debug.enabled) {
|
|
1729
|
+
console.log("Solution to layout constraints:");
|
|
1730
|
+
console.table(
|
|
1731
|
+
Object.entries(kVars).map(([key, kvar]) => ({
|
|
1732
|
+
var: key,
|
|
1733
|
+
val: kvar.value()
|
|
1734
|
+
}))
|
|
1699
1735
|
);
|
|
1700
|
-
const trace = solution[0];
|
|
1701
|
-
if (!trace) {
|
|
1702
|
-
this.renderError("Failed to route net islands");
|
|
1703
|
-
return;
|
|
1704
|
-
}
|
|
1705
|
-
db.pcb_trace.insert(trace);
|
|
1706
1736
|
}
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1737
|
+
const bounds = {
|
|
1738
|
+
left: Infinity,
|
|
1739
|
+
right: -Infinity,
|
|
1740
|
+
top: -Infinity,
|
|
1741
|
+
bottom: Infinity
|
|
1742
|
+
};
|
|
1743
|
+
for (const {
|
|
1744
|
+
selector,
|
|
1745
|
+
bounds: { width, height }
|
|
1746
|
+
} of involvedComponents) {
|
|
1747
|
+
const kvx = getKVar(`${selector}_x`);
|
|
1748
|
+
const kvy = getKVar(`${selector}_y`);
|
|
1749
|
+
const newLeft = kvx.value() - width / 2;
|
|
1750
|
+
const newRight = kvx.value() + width / 2;
|
|
1751
|
+
const newTop = kvy.value() + height / 2;
|
|
1752
|
+
const newBottom = kvy.value() - height / 2;
|
|
1753
|
+
bounds.left = Math.min(bounds.left, newLeft);
|
|
1754
|
+
bounds.right = Math.max(bounds.right, newRight);
|
|
1755
|
+
bounds.top = Math.max(bounds.top, newTop);
|
|
1756
|
+
bounds.bottom = Math.min(bounds.bottom, newBottom);
|
|
1717
1757
|
}
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
minY = Math.min(minY, y - height2 / 2);
|
|
1733
|
-
maxX = Math.max(maxX, x + width2 / 2);
|
|
1734
|
-
maxY = Math.max(maxY, y + height2 / 2);
|
|
1735
|
-
} else if (child.componentName === "Footprint") {
|
|
1736
|
-
const childBounds = getBoundsOfPcbComponents(child.children);
|
|
1737
|
-
minX = Math.min(minX, childBounds.minX);
|
|
1738
|
-
minY = Math.min(minY, childBounds.minY);
|
|
1739
|
-
maxX = Math.max(maxX, childBounds.maxX);
|
|
1740
|
-
maxY = Math.max(maxY, childBounds.maxY);
|
|
1758
|
+
const globalOffset = {
|
|
1759
|
+
x: -(bounds.right + bounds.left) / 2,
|
|
1760
|
+
y: -(bounds.top + bounds.bottom) / 2
|
|
1761
|
+
};
|
|
1762
|
+
const containerPos = this.getPrimitiveContainer()._getGlobalPcbPositionBeforeLayout();
|
|
1763
|
+
globalOffset.x += containerPos.x;
|
|
1764
|
+
globalOffset.y += containerPos.y;
|
|
1765
|
+
for (const { component, selector } of involvedComponents) {
|
|
1766
|
+
const kvx = getKVar(`${selector}_x`);
|
|
1767
|
+
const kvy = getKVar(`${selector}_y`);
|
|
1768
|
+
component._setPositionFromLayout({
|
|
1769
|
+
x: kvx.value() + globalOffset.x,
|
|
1770
|
+
y: kvy.value() + globalOffset.y
|
|
1771
|
+
});
|
|
1741
1772
|
}
|
|
1742
1773
|
}
|
|
1743
|
-
|
|
1744
|
-
let height = maxY - minY;
|
|
1745
|
-
if (width < 0) width = 0;
|
|
1746
|
-
if (height < 0) height = 0;
|
|
1747
|
-
return {
|
|
1748
|
-
minX,
|
|
1749
|
-
minY,
|
|
1750
|
-
maxX,
|
|
1751
|
-
maxY,
|
|
1752
|
-
width,
|
|
1753
|
-
height
|
|
1754
|
-
};
|
|
1755
|
-
}
|
|
1774
|
+
};
|
|
1756
1775
|
|
|
1757
1776
|
// lib/components/base-components/NormalComponent.ts
|
|
1758
|
-
import { rotation } from "circuit-json";
|
|
1759
1777
|
var rotation3 = z4.object({
|
|
1760
1778
|
x: rotation,
|
|
1761
1779
|
y: rotation,
|
|
@@ -1786,6 +1804,36 @@ var NormalComponent = class extends PrimitiveComponent {
|
|
|
1786
1804
|
initPorts() {
|
|
1787
1805
|
const { config } = this;
|
|
1788
1806
|
const portsToCreate = [];
|
|
1807
|
+
const schPortArrangement = this._parsedProps.schPortArrangement;
|
|
1808
|
+
if (schPortArrangement) {
|
|
1809
|
+
for (const side in schPortArrangement) {
|
|
1810
|
+
const pins = schPortArrangement[side].pins;
|
|
1811
|
+
if (Array.isArray(pins)) {
|
|
1812
|
+
for (const pinNumber of pins) {
|
|
1813
|
+
portsToCreate.push(new Port({ pinNumber }));
|
|
1814
|
+
}
|
|
1815
|
+
}
|
|
1816
|
+
}
|
|
1817
|
+
}
|
|
1818
|
+
const pinLabels = this._parsedProps.pinLabels;
|
|
1819
|
+
if (pinLabels) {
|
|
1820
|
+
for (let [pinNumber, label] of Object.entries(pinLabels)) {
|
|
1821
|
+
pinNumber = pinNumber.replace("pin", "");
|
|
1822
|
+
let existingPort = portsToCreate.find(
|
|
1823
|
+
(p) => p._parsedProps.pinNumber === Number(pinNumber)
|
|
1824
|
+
);
|
|
1825
|
+
if (!existingPort) {
|
|
1826
|
+
existingPort = new Port({
|
|
1827
|
+
pinNumber: parseInt(pinNumber),
|
|
1828
|
+
name: label
|
|
1829
|
+
});
|
|
1830
|
+
portsToCreate.push(existingPort);
|
|
1831
|
+
} else {
|
|
1832
|
+
existingPort.externallyAddedAliases.push(label);
|
|
1833
|
+
existingPort.props.name = label;
|
|
1834
|
+
}
|
|
1835
|
+
}
|
|
1836
|
+
}
|
|
1789
1837
|
if (config.schematicSymbolName) {
|
|
1790
1838
|
const sym = symbols2[`${config.schematicSymbolName}_horz`];
|
|
1791
1839
|
if (!sym) return;
|
|
@@ -1800,21 +1848,9 @@ var NormalComponent = class extends PrimitiveComponent {
|
|
|
1800
1848
|
return;
|
|
1801
1849
|
}
|
|
1802
1850
|
const portsFromFootprint = this.getPortsFromFootprint();
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
for (let [pinNumber, label] of Object.entries(pinLabels)) {
|
|
1807
|
-
pinNumber = pinNumber.replace("pin", "");
|
|
1808
|
-
const existingPort = portsToCreate.find(
|
|
1809
|
-
(p) => p._parsedProps.pinNumber === Number(pinNumber)
|
|
1810
|
-
);
|
|
1811
|
-
if (!existingPort) {
|
|
1812
|
-
throw new Error(
|
|
1813
|
-
`Could not find port for pin number ${pinNumber} in chip ${this.getString()}`
|
|
1814
|
-
);
|
|
1815
|
-
}
|
|
1816
|
-
existingPort.externallyAddedAliases.push(label);
|
|
1817
|
-
existingPort.props.name = label;
|
|
1851
|
+
for (const port of portsFromFootprint) {
|
|
1852
|
+
if (!portsToCreate.some((p) => p.isMatchingAnyOf(port.getNameAndAliases()))) {
|
|
1853
|
+
portsToCreate.push(port);
|
|
1818
1854
|
}
|
|
1819
1855
|
}
|
|
1820
1856
|
if (portsToCreate.length > 0) {
|
|
@@ -3122,9 +3158,6 @@ var underscorifyPortArrangement = (portArrangement) => {
|
|
|
3122
3158
|
return void 0;
|
|
3123
3159
|
};
|
|
3124
3160
|
|
|
3125
|
-
// lib/utils/schematic/getAllDimensionsForSchematicBox.ts
|
|
3126
|
-
import "circuit-json";
|
|
3127
|
-
|
|
3128
3161
|
// lib/utils/schematic/getSizeOfSidesFromPortArrangement.ts
|
|
3129
3162
|
var hasExplicitPinMapping = (pa) => {
|
|
3130
3163
|
for (const side of [
|
|
@@ -3155,8 +3188,9 @@ var getSizeOfSidesFromPortArrangement = (pa) => {
|
|
|
3155
3188
|
};
|
|
3156
3189
|
|
|
3157
3190
|
// lib/utils/schematic/getAllDimensionsForSchematicBox.ts
|
|
3158
|
-
|
|
3159
|
-
|
|
3191
|
+
function isExplicitPinMappingArrangement(arrangement) {
|
|
3192
|
+
return arrangement.leftSide !== void 0;
|
|
3193
|
+
}
|
|
3160
3194
|
var getAllDimensionsForSchematicBox = (params) => {
|
|
3161
3195
|
const portDistanceFromEdge = params.portDistanceFromEdge ?? params.schPinSpacing * 2;
|
|
3162
3196
|
let sidePinCounts = params.schPortArrangement ? getSizeOfSidesFromPortArrangement(params.schPortArrangement) : null;
|
|
@@ -3195,7 +3229,7 @@ var getAllDimensionsForSchematicBox = (params) => {
|
|
|
3195
3229
|
let currentDistanceFromEdge = 0;
|
|
3196
3230
|
let truePinIndex = 0;
|
|
3197
3231
|
for (let sideIndex = 0; sideIndex < sidePinCounts.leftSize; sideIndex++) {
|
|
3198
|
-
const pinNumber = truePinIndex + 1;
|
|
3232
|
+
const pinNumber = params.schPortArrangement && isExplicitPinMappingArrangement(params.schPortArrangement) ? params.schPortArrangement?.leftSide?.pins[sideIndex] : truePinIndex + 1;
|
|
3199
3233
|
const pinStyle = params.schPinStyle?.[`pin${pinNumber}`] ?? params.schPinStyle?.[pinNumber];
|
|
3200
3234
|
if (pinStyle?.topMargin) {
|
|
3201
3235
|
currentDistanceFromEdge += pinStyle.topMargin;
|
|
@@ -3219,7 +3253,7 @@ var getAllDimensionsForSchematicBox = (params) => {
|
|
|
3219
3253
|
}
|
|
3220
3254
|
currentDistanceFromEdge = 0;
|
|
3221
3255
|
for (let sideIndex = 0; sideIndex < sidePinCounts.bottomSize; sideIndex++) {
|
|
3222
|
-
const pinNumber = truePinIndex + 1;
|
|
3256
|
+
const pinNumber = params.schPortArrangement && isExplicitPinMappingArrangement(params.schPortArrangement) ? params.schPortArrangement.bottomSide?.pins[sideIndex] : truePinIndex + 1;
|
|
3223
3257
|
const pinStyle = params.schPinStyle?.[`pin${pinNumber}`] ?? params.schPinStyle?.[pinNumber];
|
|
3224
3258
|
if (pinStyle?.leftMargin) {
|
|
3225
3259
|
currentDistanceFromEdge += pinStyle.leftMargin;
|
|
@@ -3243,7 +3277,7 @@ var getAllDimensionsForSchematicBox = (params) => {
|
|
|
3243
3277
|
}
|
|
3244
3278
|
currentDistanceFromEdge = 0;
|
|
3245
3279
|
for (let sideIndex = 0; sideIndex < sidePinCounts.rightSize; sideIndex++) {
|
|
3246
|
-
const pinNumber = truePinIndex + 1;
|
|
3280
|
+
const pinNumber = params.schPortArrangement && isExplicitPinMappingArrangement(params.schPortArrangement) ? params.schPortArrangement.rightSide?.pins[sideIndex] : truePinIndex + 1;
|
|
3247
3281
|
const pinStyle = params.schPinStyle?.[`pin${pinNumber}`] ?? params.schPinStyle?.[pinNumber];
|
|
3248
3282
|
if (pinStyle?.bottomMargin) {
|
|
3249
3283
|
currentDistanceFromEdge += pinStyle.bottomMargin;
|
|
@@ -3267,7 +3301,7 @@ var getAllDimensionsForSchematicBox = (params) => {
|
|
|
3267
3301
|
}
|
|
3268
3302
|
currentDistanceFromEdge = 0;
|
|
3269
3303
|
for (let sideIndex = 0; sideIndex < sidePinCounts.topSize; sideIndex++) {
|
|
3270
|
-
const pinNumber = truePinIndex + 1;
|
|
3304
|
+
const pinNumber = params.schPortArrangement && isExplicitPinMappingArrangement(params.schPortArrangement) ? params.schPortArrangement.topSide?.pins[sideIndex] : truePinIndex + 1;
|
|
3271
3305
|
const pinStyle = params.schPinStyle?.[`pin${pinNumber}`] ?? params.schPinStyle?.[pinNumber];
|
|
3272
3306
|
if (pinStyle?.rightMargin) {
|
|
3273
3307
|
currentDistanceFromEdge += pinStyle.rightMargin;
|
|
@@ -3347,9 +3381,7 @@ var getAllDimensionsForSchematicBox = (params) => {
|
|
|
3347
3381
|
(p) => p.pinNumber.toString() === pinNumber.toString()
|
|
3348
3382
|
);
|
|
3349
3383
|
if (!port) {
|
|
3350
|
-
|
|
3351
|
-
`Could not find port for pin number ${pinNumber}, available pins: ${truePortsWithPositions.map((tp) => tp.pinNumber).join(", ")}`
|
|
3352
|
-
);
|
|
3384
|
+
return { x: 0, y: 0 };
|
|
3353
3385
|
}
|
|
3354
3386
|
return port;
|
|
3355
3387
|
},
|