@tscircuit/core 0.0.27 → 0.0.29
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 +22 -3
- package/dist/index.js +72 -10
- package/lib/components/base-components/NormalComponent.ts +31 -4
- package/lib/components/base-components/PrimitiveComponent.ts +26 -6
- package/lib/components/base-components/Renderable.ts +1 -1
- package/lib/components/primitive-components/PlatedHole.ts +13 -0
- package/lib/components/primitive-components/SmtPad.ts +13 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -36,7 +36,7 @@ declare class Circuit {
|
|
|
36
36
|
}
|
|
37
37
|
declare const Project: typeof Circuit;
|
|
38
38
|
|
|
39
|
-
declare const orderedRenderPhases: readonly ["ReactSubtreesRender", "CreateNetsFromProps", "CreateTracesFromProps", "SourceRender", "SourceParentAttachment", "PortDiscovery", "PortMatching", "SourceTraceRender", "SchematicComponentRender", "SchematicLayout", "SchematicPortRender", "SchematicTraceRender", "PcbComponentRender", "PcbPortRender", "PcbPrimitiveRender", "PcbParentAttachment", "PcbLayout", "PcbTraceRender", "PcbRouteNetIslands", "
|
|
39
|
+
declare const orderedRenderPhases: readonly ["ReactSubtreesRender", "CreateNetsFromProps", "CreateTracesFromProps", "SourceRender", "SourceParentAttachment", "PortDiscovery", "PortMatching", "SourceTraceRender", "SchematicComponentRender", "SchematicLayout", "SchematicPortRender", "SchematicTraceRender", "PcbComponentRender", "PcbPortRender", "PcbPrimitiveRender", "PcbParentAttachment", "PcbLayout", "PcbTraceRender", "PcbRouteNetIslands", "PcbComponentSizeCalculation", "CadModelRender"];
|
|
40
40
|
type RenderPhase = (typeof orderedRenderPhases)[number];
|
|
41
41
|
type RenderPhaseFn<K extends RenderPhase = RenderPhase> = `doInitial${K}` | `update${K}` | `remove${K}`;
|
|
42
42
|
type RenderPhaseStates = Record<RenderPhase, {
|
|
@@ -119,7 +119,10 @@ declare abstract class PrimitiveComponent<ZodProps extends ZodType = any> extend
|
|
|
119
119
|
computePcbPropsTransform(): Matrix;
|
|
120
120
|
/**
|
|
121
121
|
* Compute a transformation matrix combining all parent transforms for PCB
|
|
122
|
-
* components
|
|
122
|
+
* components, including this component's translation and rotation.
|
|
123
|
+
*
|
|
124
|
+
* This is used to compute this component's position as well as all children
|
|
125
|
+
* components positions
|
|
123
126
|
*/
|
|
124
127
|
computePcbGlobalTransform(): Matrix;
|
|
125
128
|
/**
|
|
@@ -167,6 +170,10 @@ declare abstract class PrimitiveComponent<ZodProps extends ZodType = any> extend
|
|
|
167
170
|
getNameAndAliases(): string[];
|
|
168
171
|
isMatchingNameOrAlias(name: string): boolean;
|
|
169
172
|
isMatchingAnyOf(aliases: Array<string | number>): boolean;
|
|
173
|
+
getPcbSize(): {
|
|
174
|
+
width: number;
|
|
175
|
+
height: number;
|
|
176
|
+
};
|
|
170
177
|
doesSelectorMatch(selector: string): boolean;
|
|
171
178
|
getSubcircuit(): PrimitiveComponent;
|
|
172
179
|
selectAll(selector: string): PrimitiveComponent[];
|
|
@@ -545,7 +552,11 @@ declare class NormalComponent<ZodProps extends ZodType = any, PortNames extends
|
|
|
545
552
|
*/
|
|
546
553
|
doInitialSchematicComponentRender(): void;
|
|
547
554
|
doInitialPcbComponentRender(): void;
|
|
548
|
-
|
|
555
|
+
/**
|
|
556
|
+
* At this stage, the smtpads/pcb primitives are placed, so we can compute
|
|
557
|
+
* the width/height of the component
|
|
558
|
+
*/
|
|
559
|
+
doInitialPcbComponentSizeCalculation(): void;
|
|
549
560
|
_renderReactSubtree(element: ReactElement): ReactSubtree;
|
|
550
561
|
doInitialReactSubtreesRender(): void;
|
|
551
562
|
add(componentOrElm: PrimitiveComponent | ReactElement): void;
|
|
@@ -702,6 +713,10 @@ declare class SmtPad extends PrimitiveComponent<typeof smtPadProps> {
|
|
|
702
713
|
height?: string | number | undefined;
|
|
703
714
|
}>]>;
|
|
704
715
|
};
|
|
716
|
+
getPcbSize(): {
|
|
717
|
+
width: number;
|
|
718
|
+
height: number;
|
|
719
|
+
};
|
|
705
720
|
doInitialPortMatching(): void;
|
|
706
721
|
doInitialPcbPrimitiveRender(): void;
|
|
707
722
|
}
|
|
@@ -3326,6 +3341,10 @@ declare class PlatedHole extends PrimitiveComponent<typeof platedHoleProps> {
|
|
|
3326
3341
|
portHints?: (string | number)[] | undefined;
|
|
3327
3342
|
}>]>;
|
|
3328
3343
|
};
|
|
3344
|
+
getPcbSize(): {
|
|
3345
|
+
width: number;
|
|
3346
|
+
height: number;
|
|
3347
|
+
};
|
|
3329
3348
|
doInitialPortMatching(): void;
|
|
3330
3349
|
doInitialPcbPrimitiveRender(): void;
|
|
3331
3350
|
}
|
package/dist/index.js
CHANGED
|
@@ -56,8 +56,8 @@ var orderedRenderPhases = [
|
|
|
56
56
|
"PcbLayout",
|
|
57
57
|
"PcbTraceRender",
|
|
58
58
|
"PcbRouteNetIslands",
|
|
59
|
-
"
|
|
60
|
-
"
|
|
59
|
+
"PcbComponentSizeCalculation",
|
|
60
|
+
"CadModelRender"
|
|
61
61
|
];
|
|
62
62
|
var globalRenderCounter = 0;
|
|
63
63
|
var Renderable = class {
|
|
@@ -239,9 +239,23 @@ var PrimitiveComponent = class extends Renderable {
|
|
|
239
239
|
}
|
|
240
240
|
/**
|
|
241
241
|
* Compute a transformation matrix combining all parent transforms for PCB
|
|
242
|
-
* components
|
|
242
|
+
* components, including this component's translation and rotation.
|
|
243
|
+
*
|
|
244
|
+
* This is used to compute this component's position as well as all children
|
|
245
|
+
* components positions
|
|
243
246
|
*/
|
|
244
247
|
computePcbGlobalTransform() {
|
|
248
|
+
const { _parsedProps: props } = this;
|
|
249
|
+
const manualPlacement = this.getSubcircuit()._getManualPlacementForComponent(this);
|
|
250
|
+
if (manualPlacement && this.props.pcbX === void 0 && this.props.pcbY === void 0) {
|
|
251
|
+
return compose(
|
|
252
|
+
this.parent?.computePcbGlobalTransform() ?? identity(),
|
|
253
|
+
compose(
|
|
254
|
+
translate(manualPlacement.x, manualPlacement.y),
|
|
255
|
+
rotate((props.pcbRotation ?? 0) * Math.PI / 180)
|
|
256
|
+
)
|
|
257
|
+
);
|
|
258
|
+
}
|
|
245
259
|
return compose(
|
|
246
260
|
this.parent?.computePcbGlobalTransform() ?? identity(),
|
|
247
261
|
this.computePcbPropsTransform()
|
|
@@ -296,10 +310,6 @@ var PrimitiveComponent = class extends Renderable {
|
|
|
296
310
|
return null;
|
|
297
311
|
}
|
|
298
312
|
getGlobalPcbPosition() {
|
|
299
|
-
const manualPlacement = this.getSubcircuit()._getManualPlacementForComponent(this);
|
|
300
|
-
if (manualPlacement) {
|
|
301
|
-
return manualPlacement;
|
|
302
|
-
}
|
|
303
313
|
return applyToPoint(this.computePcbGlobalTransform(), { x: 0, y: 0 });
|
|
304
314
|
}
|
|
305
315
|
getGlobalSchematicPosition() {
|
|
@@ -360,6 +370,9 @@ var PrimitiveComponent = class extends Renderable {
|
|
|
360
370
|
(a) => aliases.map((a2) => a2.toString()).includes(a)
|
|
361
371
|
);
|
|
362
372
|
}
|
|
373
|
+
getPcbSize() {
|
|
374
|
+
throw new Error(`getPcbSize not implemented for ${this.componentName}`);
|
|
375
|
+
}
|
|
363
376
|
doesSelectorMatch(selector) {
|
|
364
377
|
const myTypeNames = [this.componentName, this.lowercaseComponentName];
|
|
365
378
|
const myClassNames = [this._parsedProps.name].filter(Boolean);
|
|
@@ -830,6 +843,18 @@ var SmtPad = class extends PrimitiveComponent {
|
|
|
830
843
|
zodProps: smtPadProps
|
|
831
844
|
};
|
|
832
845
|
}
|
|
846
|
+
getPcbSize() {
|
|
847
|
+
const { _parsedProps: props } = this;
|
|
848
|
+
if (props.shape === "circle") {
|
|
849
|
+
return { width: props.radius * 2, height: props.radius * 2 };
|
|
850
|
+
}
|
|
851
|
+
if (props.shape === "rect") {
|
|
852
|
+
return { width: props.width, height: props.height };
|
|
853
|
+
}
|
|
854
|
+
throw new Error(
|
|
855
|
+
`getPcbSize for shape "${props.shape}" not implemented for ${this.componentName}`
|
|
856
|
+
);
|
|
857
|
+
}
|
|
833
858
|
doInitialPortMatching() {
|
|
834
859
|
const parentPorts = (this.parent?.children ?? []).filter(
|
|
835
860
|
(c) => c.componentName === "Port"
|
|
@@ -934,6 +959,18 @@ var PlatedHole = class extends PrimitiveComponent {
|
|
|
934
959
|
zodProps: platedHoleProps
|
|
935
960
|
};
|
|
936
961
|
}
|
|
962
|
+
getPcbSize() {
|
|
963
|
+
const { _parsedProps: props } = this;
|
|
964
|
+
if (props.shape === "circle") {
|
|
965
|
+
return { width: props.outerDiameter, height: props.outerDiameter };
|
|
966
|
+
}
|
|
967
|
+
if (props.shape === "oval") {
|
|
968
|
+
return { width: props.outerWidth, height: props.outerHeight };
|
|
969
|
+
}
|
|
970
|
+
throw new Error(
|
|
971
|
+
`getPcbSize for shape "${props.shape}" not implemented for ${this.componentName}`
|
|
972
|
+
);
|
|
973
|
+
}
|
|
937
974
|
doInitialPortMatching() {
|
|
938
975
|
const parentPorts = (this.parent?.children ?? []).filter(
|
|
939
976
|
(c) => c.componentName === "Port"
|
|
@@ -1307,8 +1344,8 @@ var NormalComponent = class extends PrimitiveComponent {
|
|
|
1307
1344
|
const { db } = this.project;
|
|
1308
1345
|
const { _parsedProps: props } = this;
|
|
1309
1346
|
const pcb_component = db.pcb_component.insert({
|
|
1310
|
-
center:
|
|
1311
|
-
// width/height are computed in the
|
|
1347
|
+
center: this.getGlobalPcbPosition(),
|
|
1348
|
+
// width/height are computed in the PcbComponentSizeCalculation phase
|
|
1312
1349
|
width: 0,
|
|
1313
1350
|
height: 0,
|
|
1314
1351
|
layer: props.layer ?? "top",
|
|
@@ -1317,9 +1354,34 @@ var NormalComponent = class extends PrimitiveComponent {
|
|
|
1317
1354
|
});
|
|
1318
1355
|
this.pcb_component_id = pcb_component.pcb_component_id;
|
|
1319
1356
|
}
|
|
1320
|
-
|
|
1357
|
+
/**
|
|
1358
|
+
* At this stage, the smtpads/pcb primitives are placed, so we can compute
|
|
1359
|
+
* the width/height of the component
|
|
1360
|
+
*/
|
|
1361
|
+
doInitialPcbComponentSizeCalculation() {
|
|
1362
|
+
if (!this.pcb_component_id) return;
|
|
1321
1363
|
const { db } = this.project;
|
|
1322
1364
|
const { _parsedProps: props } = this;
|
|
1365
|
+
let minX = Infinity;
|
|
1366
|
+
let minY = Infinity;
|
|
1367
|
+
let maxX = -Infinity;
|
|
1368
|
+
let maxY = -Infinity;
|
|
1369
|
+
for (const child of this.children) {
|
|
1370
|
+
if (child.isPcbPrimitive) {
|
|
1371
|
+
const { x, y } = child.getGlobalPcbPosition();
|
|
1372
|
+
const { width: width2, height: height2 } = child.getPcbSize();
|
|
1373
|
+
minX = Math.min(minX, x - width2 / 2);
|
|
1374
|
+
minY = Math.min(minY, y - height2 / 2);
|
|
1375
|
+
maxX = Math.max(maxX, x + width2 / 2);
|
|
1376
|
+
maxY = Math.max(maxY, y + height2 / 2);
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
const width = maxX - minX;
|
|
1380
|
+
const height = maxY - minY;
|
|
1381
|
+
db.pcb_component.update(this.pcb_component_id, {
|
|
1382
|
+
width,
|
|
1383
|
+
height
|
|
1384
|
+
});
|
|
1323
1385
|
}
|
|
1324
1386
|
_renderReactSubtree(element) {
|
|
1325
1387
|
return {
|
|
@@ -194,8 +194,8 @@ export class NormalComponent<
|
|
|
194
194
|
const { db } = this.project!
|
|
195
195
|
const { _parsedProps: props } = this
|
|
196
196
|
const pcb_component = db.pcb_component.insert({
|
|
197
|
-
center:
|
|
198
|
-
// width/height are computed in the
|
|
197
|
+
center: this.getGlobalPcbPosition(),
|
|
198
|
+
// width/height are computed in the PcbComponentSizeCalculation phase
|
|
199
199
|
width: 0,
|
|
200
200
|
height: 0,
|
|
201
201
|
layer: props.layer ?? "top",
|
|
@@ -205,11 +205,38 @@ export class NormalComponent<
|
|
|
205
205
|
this.pcb_component_id = pcb_component.pcb_component_id
|
|
206
206
|
}
|
|
207
207
|
|
|
208
|
-
|
|
208
|
+
/**
|
|
209
|
+
* At this stage, the smtpads/pcb primitives are placed, so we can compute
|
|
210
|
+
* the width/height of the component
|
|
211
|
+
*/
|
|
212
|
+
doInitialPcbComponentSizeCalculation(): void {
|
|
213
|
+
if (!this.pcb_component_id) return
|
|
209
214
|
const { db } = this.project!
|
|
210
215
|
const { _parsedProps: props } = this
|
|
211
216
|
|
|
212
|
-
|
|
217
|
+
let minX = Infinity
|
|
218
|
+
let minY = Infinity
|
|
219
|
+
let maxX = -Infinity
|
|
220
|
+
let maxY = -Infinity
|
|
221
|
+
|
|
222
|
+
for (const child of this.children) {
|
|
223
|
+
if (child.isPcbPrimitive) {
|
|
224
|
+
const { x, y } = child.getGlobalPcbPosition()
|
|
225
|
+
const { width, height } = child.getPcbSize()
|
|
226
|
+
minX = Math.min(minX, x - width / 2)
|
|
227
|
+
minY = Math.min(minY, y - height / 2)
|
|
228
|
+
maxX = Math.max(maxX, x + width / 2)
|
|
229
|
+
maxY = Math.max(maxY, y + height / 2)
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const width = maxX - minX
|
|
234
|
+
const height = maxY - minY
|
|
235
|
+
|
|
236
|
+
db.pcb_component.update(this.pcb_component_id!, {
|
|
237
|
+
width,
|
|
238
|
+
height,
|
|
239
|
+
})
|
|
213
240
|
}
|
|
214
241
|
|
|
215
242
|
_renderReactSubtree(element: ReactElement): ReactSubtree {
|
|
@@ -126,9 +126,31 @@ export abstract class PrimitiveComponent<
|
|
|
126
126
|
|
|
127
127
|
/**
|
|
128
128
|
* Compute a transformation matrix combining all parent transforms for PCB
|
|
129
|
-
* components
|
|
129
|
+
* components, including this component's translation and rotation.
|
|
130
|
+
*
|
|
131
|
+
* This is used to compute this component's position as well as all children
|
|
132
|
+
* components positions
|
|
130
133
|
*/
|
|
131
134
|
computePcbGlobalTransform(): Matrix {
|
|
135
|
+
const { _parsedProps: props } = this
|
|
136
|
+
const manualPlacement =
|
|
137
|
+
this.getSubcircuit()._getManualPlacementForComponent(this)
|
|
138
|
+
|
|
139
|
+
// pcbX or pcbY will override the manual placement
|
|
140
|
+
if (
|
|
141
|
+
manualPlacement &&
|
|
142
|
+
this.props.pcbX === undefined &&
|
|
143
|
+
this.props.pcbY === undefined
|
|
144
|
+
) {
|
|
145
|
+
return compose(
|
|
146
|
+
this.parent?.computePcbGlobalTransform() ?? identity(),
|
|
147
|
+
compose(
|
|
148
|
+
translate(manualPlacement.x, manualPlacement.y),
|
|
149
|
+
rotate(((props.pcbRotation ?? 0) * Math.PI) / 180),
|
|
150
|
+
),
|
|
151
|
+
)
|
|
152
|
+
}
|
|
153
|
+
|
|
132
154
|
return compose(
|
|
133
155
|
this.parent?.computePcbGlobalTransform() ?? identity(),
|
|
134
156
|
this.computePcbPropsTransform(),
|
|
@@ -198,11 +220,6 @@ export abstract class PrimitiveComponent<
|
|
|
198
220
|
}
|
|
199
221
|
|
|
200
222
|
getGlobalPcbPosition(): { x: number; y: number } {
|
|
201
|
-
const manualPlacement =
|
|
202
|
-
this.getSubcircuit()._getManualPlacementForComponent(this)
|
|
203
|
-
if (manualPlacement) {
|
|
204
|
-
return manualPlacement
|
|
205
|
-
}
|
|
206
223
|
return applyToPoint(this.computePcbGlobalTransform(), { x: 0, y: 0 })
|
|
207
224
|
}
|
|
208
225
|
|
|
@@ -281,6 +298,9 @@ export abstract class PrimitiveComponent<
|
|
|
281
298
|
aliases.map((a) => a.toString()).includes(a),
|
|
282
299
|
)
|
|
283
300
|
}
|
|
301
|
+
getPcbSize(): { width: number; height: number } {
|
|
302
|
+
throw new Error(`getPcbSize not implemented for ${this.componentName}`)
|
|
303
|
+
}
|
|
284
304
|
|
|
285
305
|
doesSelectorMatch(selector: string): boolean {
|
|
286
306
|
const myTypeNames = [this.componentName, this.lowercaseComponentName]
|
|
@@ -14,6 +14,19 @@ export class PlatedHole extends PrimitiveComponent<typeof platedHoleProps> {
|
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
getPcbSize(): { width: number; height: number } {
|
|
18
|
+
const { _parsedProps: props } = this
|
|
19
|
+
if (props.shape === "circle") {
|
|
20
|
+
return { width: props.outerDiameter, height: props.outerDiameter }
|
|
21
|
+
}
|
|
22
|
+
if (props.shape === "oval") {
|
|
23
|
+
return { width: props.outerWidth, height: props.outerHeight }
|
|
24
|
+
}
|
|
25
|
+
throw new Error(
|
|
26
|
+
`getPcbSize for shape "${(props as any).shape}" not implemented for ${this.componentName}`,
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
|
|
17
30
|
doInitialPortMatching(): void {
|
|
18
31
|
const parentPorts = (this.parent?.children ?? []).filter(
|
|
19
32
|
(c) => c.componentName === "Port",
|
|
@@ -18,6 +18,19 @@ export class SmtPad extends PrimitiveComponent<typeof smtPadProps> {
|
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
getPcbSize(): { width: number; height: number } {
|
|
22
|
+
const { _parsedProps: props } = this
|
|
23
|
+
if (props.shape === "circle") {
|
|
24
|
+
return { width: props.radius! * 2, height: props.radius! * 2 }
|
|
25
|
+
}
|
|
26
|
+
if (props.shape === "rect") {
|
|
27
|
+
return { width: props.width!, height: props.height! }
|
|
28
|
+
}
|
|
29
|
+
throw new Error(
|
|
30
|
+
`getPcbSize for shape "${(props as any).shape}" not implemented for ${this.componentName}`,
|
|
31
|
+
)
|
|
32
|
+
}
|
|
33
|
+
|
|
21
34
|
doInitialPortMatching(): void {
|
|
22
35
|
const parentPorts = (this.parent?.children ?? []).filter(
|
|
23
36
|
(c) => c.componentName === "Port",
|