@tscircuit/core 0.0.28 → 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 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", "CadModelRender", "PcbAnalysis"];
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, {
@@ -170,6 +170,10 @@ declare abstract class PrimitiveComponent<ZodProps extends ZodType = any> extend
170
170
  getNameAndAliases(): string[];
171
171
  isMatchingNameOrAlias(name: string): boolean;
172
172
  isMatchingAnyOf(aliases: Array<string | number>): boolean;
173
+ getPcbSize(): {
174
+ width: number;
175
+ height: number;
176
+ };
173
177
  doesSelectorMatch(selector: string): boolean;
174
178
  getSubcircuit(): PrimitiveComponent;
175
179
  selectAll(selector: string): PrimitiveComponent[];
@@ -548,7 +552,11 @@ declare class NormalComponent<ZodProps extends ZodType = any, PortNames extends
548
552
  */
549
553
  doInitialSchematicComponentRender(): void;
550
554
  doInitialPcbComponentRender(): void;
551
- doInitialPcbAnalysis(): void;
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;
552
560
  _renderReactSubtree(element: ReactElement): ReactSubtree;
553
561
  doInitialReactSubtreesRender(): void;
554
562
  add(componentOrElm: PrimitiveComponent | ReactElement): void;
@@ -705,6 +713,10 @@ declare class SmtPad extends PrimitiveComponent<typeof smtPadProps> {
705
713
  height?: string | number | undefined;
706
714
  }>]>;
707
715
  };
716
+ getPcbSize(): {
717
+ width: number;
718
+ height: number;
719
+ };
708
720
  doInitialPortMatching(): void;
709
721
  doInitialPcbPrimitiveRender(): void;
710
722
  }
@@ -3329,6 +3341,10 @@ declare class PlatedHole extends PrimitiveComponent<typeof platedHoleProps> {
3329
3341
  portHints?: (string | number)[] | undefined;
3330
3342
  }>]>;
3331
3343
  };
3344
+ getPcbSize(): {
3345
+ width: number;
3346
+ height: number;
3347
+ };
3332
3348
  doInitialPortMatching(): void;
3333
3349
  doInitialPcbPrimitiveRender(): void;
3334
3350
  }
package/dist/index.js CHANGED
@@ -56,8 +56,8 @@ var orderedRenderPhases = [
56
56
  "PcbLayout",
57
57
  "PcbTraceRender",
58
58
  "PcbRouteNetIslands",
59
- "CadModelRender",
60
- "PcbAnalysis"
59
+ "PcbComponentSizeCalculation",
60
+ "CadModelRender"
61
61
  ];
62
62
  var globalRenderCounter = 0;
63
63
  var Renderable = class {
@@ -370,6 +370,9 @@ var PrimitiveComponent = class extends Renderable {
370
370
  (a) => aliases.map((a2) => a2.toString()).includes(a)
371
371
  );
372
372
  }
373
+ getPcbSize() {
374
+ throw new Error(`getPcbSize not implemented for ${this.componentName}`);
375
+ }
373
376
  doesSelectorMatch(selector) {
374
377
  const myTypeNames = [this.componentName, this.lowercaseComponentName];
375
378
  const myClassNames = [this._parsedProps.name].filter(Boolean);
@@ -840,6 +843,18 @@ var SmtPad = class extends PrimitiveComponent {
840
843
  zodProps: smtPadProps
841
844
  };
842
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
+ }
843
858
  doInitialPortMatching() {
844
859
  const parentPorts = (this.parent?.children ?? []).filter(
845
860
  (c) => c.componentName === "Port"
@@ -944,6 +959,18 @@ var PlatedHole = class extends PrimitiveComponent {
944
959
  zodProps: platedHoleProps
945
960
  };
946
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
+ }
947
974
  doInitialPortMatching() {
948
975
  const parentPorts = (this.parent?.children ?? []).filter(
949
976
  (c) => c.componentName === "Port"
@@ -1317,8 +1344,8 @@ var NormalComponent = class extends PrimitiveComponent {
1317
1344
  const { db } = this.project;
1318
1345
  const { _parsedProps: props } = this;
1319
1346
  const pcb_component = db.pcb_component.insert({
1320
- center: { x: this.props.pcbX ?? 0, y: this.props.pcbY ?? 0 },
1321
- // width/height are computed in the PcbAnalysis phase
1347
+ center: this.getGlobalPcbPosition(),
1348
+ // width/height are computed in the PcbComponentSizeCalculation phase
1322
1349
  width: 0,
1323
1350
  height: 0,
1324
1351
  layer: props.layer ?? "top",
@@ -1327,9 +1354,34 @@ var NormalComponent = class extends PrimitiveComponent {
1327
1354
  });
1328
1355
  this.pcb_component_id = pcb_component.pcb_component_id;
1329
1356
  }
1330
- doInitialPcbAnalysis() {
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;
1331
1363
  const { db } = this.project;
1332
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
+ });
1333
1385
  }
1334
1386
  _renderReactSubtree(element) {
1335
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: { x: this.props.pcbX ?? 0, y: this.props.pcbY ?? 0 },
198
- // width/height are computed in the PcbAnalysis phase
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
- doInitialPcbAnalysis(): void {
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
- // TODO Examine children to compute width/height and pcbX/pcbY
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 {
@@ -298,6 +298,9 @@ export abstract class PrimitiveComponent<
298
298
  aliases.map((a) => a.toString()).includes(a),
299
299
  )
300
300
  }
301
+ getPcbSize(): { width: number; height: number } {
302
+ throw new Error(`getPcbSize not implemented for ${this.componentName}`)
303
+ }
301
304
 
302
305
  doesSelectorMatch(selector: string): boolean {
303
306
  const myTypeNames = [this.componentName, this.lowercaseComponentName]
@@ -21,8 +21,8 @@ export const orderedRenderPhases = [
21
21
  "PcbLayout",
22
22
  "PcbTraceRender",
23
23
  "PcbRouteNetIslands",
24
+ "PcbComponentSizeCalculation",
24
25
  "CadModelRender",
25
- "PcbAnalysis",
26
26
  ] as const
27
27
 
28
28
  export type RenderPhase = (typeof orderedRenderPhases)[number]
@@ -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",
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@tscircuit/core",
3
3
  "module": "index.ts",
4
4
  "type": "module",
5
- "version": "0.0.28",
5
+ "version": "0.0.29",
6
6
  "types": "dist/index.d.ts",
7
7
  "main": "dist/index.js",
8
8
  "files": [