@tscircuit/core 0.0.59 → 0.0.60

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
@@ -3773,7 +3773,7 @@ declare class PlatedHole extends PrimitiveComponent<typeof platedHoleProps> {
3773
3773
  }>]>, "top" | "bottom" | "inner1" | "inner2" | "inner3" | "inner4" | "inner5" | "inner6", "top" | "bottom" | "inner1" | "inner2" | "inner3" | "inner4" | "inner5" | "inner6" | {
3774
3774
  name: "top" | "bottom" | "inner1" | "inner2" | "inner3" | "inner4" | "inner5" | "inner6";
3775
3775
  }>>;
3776
- }, "layer" | "pcbRotation">, {
3776
+ }, "pcbRotation" | "layer">, {
3777
3777
  name: zod.ZodOptional<zod.ZodString>;
3778
3778
  shape: zod.ZodLiteral<"circle">;
3779
3779
  holeDiameter: zod.ZodEffects<zod.ZodUnion<[zod.ZodString, zod.ZodNumber]>, number, string | number>;
@@ -3808,7 +3808,7 @@ declare class PlatedHole extends PrimitiveComponent<typeof platedHoleProps> {
3808
3808
  }>]>, "top" | "bottom" | "inner1" | "inner2" | "inner3" | "inner4" | "inner5" | "inner6", "top" | "bottom" | "inner1" | "inner2" | "inner3" | "inner4" | "inner5" | "inner6" | {
3809
3809
  name: "top" | "bottom" | "inner1" | "inner2" | "inner3" | "inner4" | "inner5" | "inner6";
3810
3810
  }>>;
3811
- }, "layer" | "pcbRotation">, {
3811
+ }, "pcbRotation" | "layer">, {
3812
3812
  name: zod.ZodOptional<zod.ZodString>;
3813
3813
  shape: zod.ZodLiteral<"oval">;
3814
3814
  outerWidth: zod.ZodEffects<zod.ZodUnion<[zod.ZodString, zod.ZodNumber]>, number, string | number>;
package/dist/index.js CHANGED
@@ -1693,6 +1693,13 @@ var NormalComponent = class extends PrimitiveComponent {
1693
1693
  if (!footprint) return;
1694
1694
  if (typeof footprint === "string") {
1695
1695
  const fpSoup = fp.string(footprint).soup();
1696
+ if (this.props.layer) {
1697
+ for (const elm of fpSoup) {
1698
+ if ("layer" in elm) {
1699
+ elm.layer = this.props.layer;
1700
+ }
1701
+ }
1702
+ }
1696
1703
  const fpComponents = createComponentsFromSoup(fpSoup);
1697
1704
  this.addAll(fpComponents);
1698
1705
  }
@@ -2250,6 +2257,7 @@ var portToObjective = (port) => {
2250
2257
  layers: port.getAvailablePcbLayers()
2251
2258
  };
2252
2259
  };
2260
+ var SHOULD_USE_SINGLE_LAYER_ROUTING = false;
2253
2261
  var Trace = class extends PrimitiveComponent {
2254
2262
  source_trace_id = null;
2255
2263
  pcb_trace_id = null;
@@ -2464,7 +2472,7 @@ searched component ${targetComponent.getString()}, which has ports: ${targetComp
2464
2472
  const candidateLayerCombinations = findPossibleTraceLayerCombinations(
2465
2473
  orderedRouteObjectives
2466
2474
  );
2467
- if (candidateLayerCombinations.length === 0) {
2475
+ if (SHOULD_USE_SINGLE_LAYER_ROUTING && candidateLayerCombinations.length === 0) {
2468
2476
  this.renderError(
2469
2477
  `Could not find a common layer (using hints) for trace ${this.getString()}`
2470
2478
  );
@@ -2498,20 +2506,27 @@ searched component ${targetComponent.getString()}, which has ports: ${targetComp
2498
2506
  }
2499
2507
  }
2500
2508
  }
2501
- const candidateLayerSelections = candidateLayerCombinations[0].layer_path;
2502
- const orderedRoutePoints = orderedRouteObjectives.map((t, idx) => {
2503
- if (t.via) {
2504
- return {
2505
- ...t,
2506
- via_to_layer: candidateLayerSelections[idx]
2507
- };
2508
- }
2509
- return { ...t, layers: [candidateLayerSelections[idx]] };
2510
- });
2509
+ let orderedRoutePoints = [];
2510
+ if (candidateLayerCombinations.length === 0) {
2511
+ orderedRoutePoints = orderedRouteObjectives;
2512
+ } else {
2513
+ const candidateLayerSelections = candidateLayerCombinations[0].layer_path;
2514
+ orderedRoutePoints = orderedRouteObjectives.map((t, idx) => {
2515
+ if (t.via) {
2516
+ return {
2517
+ ...t,
2518
+ via_to_layer: candidateLayerSelections[idx]
2519
+ };
2520
+ }
2521
+ return { ...t, layers: [candidateLayerSelections[idx]] };
2522
+ });
2523
+ }
2511
2524
  const routes = [];
2512
2525
  for (const [a, b] of pairs(orderedRoutePoints)) {
2513
2526
  const dominantLayer = "via_to_layer" in a ? a.via_to_layer : null;
2514
2527
  const BOUNDS_MARGIN = 2;
2528
+ const aLayer = "layers" in a && a.layers.length === 1 ? a.layers[0] : dominantLayer ?? "top";
2529
+ const bLayer = "layers" in b && b.layers.length === 1 ? b.layers[0] : dominantLayer ?? "top";
2515
2530
  const ijump = new MultilayerIjump({
2516
2531
  OBSTACLE_MARGIN: 0.3,
2517
2532
  isRemovePathLoopsEnabled: true,
@@ -2521,8 +2536,8 @@ searched component ${targetComponent.getString()}, which has ports: ${targetComp
2521
2536
  {
2522
2537
  name: connMap.getNetConnectedToId(this.source_trace_id),
2523
2538
  pointsToConnect: [
2524
- { ...a, layer: dominantLayer ?? "top" },
2525
- { ...b, layer: dominantLayer ?? "top" }
2539
+ { ...a, layer: aLayer },
2540
+ { ...b, layer: bLayer }
2526
2541
  ]
2527
2542
  }
2528
2543
  ],
@@ -2576,36 +2591,21 @@ searched component ${targetComponent.getString()}, which has ports: ${targetComp
2576
2591
  routes.push(trace.route);
2577
2592
  }
2578
2593
  const mergedRoute = mergeRoutes(routes);
2579
- const routeWithVias = mergedRoute.flatMap((point, index) => {
2580
- const nextPoint = mergedRoute[index + 1];
2581
- if (!nextPoint) return [point];
2582
- if (point.route_type === "wire" && nextPoint.route_type === "wire" && point.layer !== nextPoint.layer) {
2583
- return [
2584
- {
2585
- route_type: "via",
2586
- from_layer: point.layer,
2587
- to_layer: nextPoint.layer,
2588
- x: nextPoint.x,
2589
- y: nextPoint.y
2590
- },
2591
- point
2592
- ];
2594
+ for (const point of mergedRoute) {
2595
+ if (point.route_type === "via") {
2596
+ db.pcb_via.insert({
2597
+ x: point.x,
2598
+ y: point.y,
2599
+ hole_diameter: 0.3,
2600
+ outer_diameter: 0.6,
2601
+ layers: [point.from_layer, point.to_layer],
2602
+ from_layer: point.from_layer,
2603
+ to_layer: point.to_layer
2604
+ });
2593
2605
  }
2594
- return [point];
2595
- });
2596
- for (const via of routeWithVias.filter((p) => p.route_type === "via")) {
2597
- db.pcb_via.insert({
2598
- x: via.x,
2599
- y: via.y,
2600
- hole_diameter: 0.3,
2601
- outer_diameter: 0.6,
2602
- layers: [via.from_layer, via.to_layer],
2603
- from_layer: via.from_layer,
2604
- to_layer: via.to_layer
2605
- });
2606
2606
  }
2607
2607
  const pcb_trace = db.pcb_trace.insert({
2608
- route: routeWithVias,
2608
+ route: mergedRoute,
2609
2609
  source_trace_id: this.source_trace_id
2610
2610
  });
2611
2611
  this._portsRoutedOnPcb = ports;
@@ -119,6 +119,14 @@ export class NormalComponent<
119
119
  if (!footprint) return
120
120
  if (typeof footprint === "string") {
121
121
  const fpSoup = fp.string(footprint).soup()
122
+ // Adjust the layer of the footprint to match the layer of the component
123
+ if (this.props.layer) {
124
+ for (const elm of fpSoup) {
125
+ if ("layer" in elm) {
126
+ elm.layer = this.props.layer
127
+ }
128
+ }
129
+ }
122
130
  const fpComponents = createComponentsFromSoup(fpSoup)
123
131
  this.addAll(fpComponents)
124
132
  }
@@ -54,6 +54,8 @@ const portToObjective = (port: Port): PcbRouteObjective => {
54
54
  }
55
55
  }
56
56
 
57
+ const SHOULD_USE_SINGLE_LAYER_ROUTING = false
58
+
57
59
  export class Trace extends PrimitiveComponent<typeof traceProps> {
58
60
  source_trace_id: string | null = null
59
61
  pcb_trace_id: string | null = null
@@ -355,7 +357,10 @@ export class Trace extends PrimitiveComponent<typeof traceProps> {
355
357
  orderedRouteObjectives,
356
358
  )
357
359
 
358
- if (candidateLayerCombinations.length === 0) {
360
+ if (
361
+ SHOULD_USE_SINGLE_LAYER_ROUTING &&
362
+ candidateLayerCombinations.length === 0
363
+ ) {
359
364
  this.renderError(
360
365
  `Could not find a common layer (using hints) for trace ${this.getString()}`,
361
366
  )
@@ -396,22 +401,27 @@ export class Trace extends PrimitiveComponent<typeof traceProps> {
396
401
  }
397
402
  }
398
403
 
399
- // TODO explore all candidate layer combinations if one fails
400
- const candidateLayerSelections = candidateLayerCombinations[0].layer_path
401
-
402
- /**
403
- * Apply the candidate layer selections to the route objectives, now we
404
- * have a set of points that have definite layers
405
- */
406
- const orderedRoutePoints = orderedRouteObjectives.map((t, idx) => {
407
- if (t.via) {
408
- return {
409
- ...t,
410
- via_to_layer: candidateLayerSelections[idx],
404
+ let orderedRoutePoints: PcbRouteObjective[] = []
405
+ if (candidateLayerCombinations.length === 0) {
406
+ orderedRoutePoints = orderedRouteObjectives
407
+ } else {
408
+ // TODO explore all candidate layer combinations if one fails
409
+ const candidateLayerSelections = candidateLayerCombinations[0].layer_path
410
+
411
+ /**
412
+ * Apply the candidate layer selections to the route objectives, now we
413
+ * have a set of points that have definite layers
414
+ */
415
+ orderedRoutePoints = orderedRouteObjectives.map((t, idx) => {
416
+ if (t.via) {
417
+ return {
418
+ ...t,
419
+ via_to_layer: candidateLayerSelections[idx],
420
+ }
411
421
  }
412
- }
413
- return { ...t, layers: [candidateLayerSelections[idx]] }
414
- })
422
+ return { ...t, layers: [candidateLayerSelections[idx]] }
423
+ })
424
+ }
415
425
 
416
426
  const routes: PCBTrace["route"][] = []
417
427
  for (const [a, b] of pairs(orderedRoutePoints)) {
@@ -419,6 +429,15 @@ export class Trace extends PrimitiveComponent<typeof traceProps> {
419
429
  "via_to_layer" in a ? (a.via_to_layer as LayerRef) : null
420
430
  const BOUNDS_MARGIN = 2 //mm
421
431
 
432
+ const aLayer =
433
+ "layers" in a && a.layers.length === 1
434
+ ? a.layers[0]
435
+ : dominantLayer ?? "top"
436
+ const bLayer =
437
+ "layers" in b && b.layers.length === 1
438
+ ? b.layers[0]
439
+ : dominantLayer ?? "top"
440
+
422
441
  const ijump = new MultilayerIjump({
423
442
  OBSTACLE_MARGIN: 0.3,
424
443
  isRemovePathLoopsEnabled: true,
@@ -428,8 +447,8 @@ export class Trace extends PrimitiveComponent<typeof traceProps> {
428
447
  {
429
448
  name: connMap.getNetConnectedToId(this.source_trace_id!)!,
430
449
  pointsToConnect: [
431
- { ...a, layer: dominantLayer ?? "top" },
432
- { ...b, layer: dominantLayer ?? "top" },
450
+ { ...a, layer: aLayer },
451
+ { ...b, layer: bLayer },
433
452
  ],
434
453
  },
435
454
  ],
@@ -490,43 +509,22 @@ export class Trace extends PrimitiveComponent<typeof traceProps> {
490
509
 
491
510
  const mergedRoute = mergeRoutes(routes)
492
511
 
493
- // Add vias where layer changes occur
494
- const routeWithVias = mergedRoute.flatMap((point, index) => {
495
- const nextPoint = mergedRoute[index + 1]
496
- if (!nextPoint) return [point]
497
- if (
498
- point.route_type === "wire" &&
499
- nextPoint.route_type === "wire" &&
500
- point.layer !== nextPoint.layer
501
- ) {
502
- return [
503
- {
504
- route_type: "via",
505
- from_layer: point.layer,
506
- to_layer: nextPoint.layer,
507
- x: nextPoint.x,
508
- y: nextPoint.y,
509
- } as (typeof mergedRoute)[number],
510
- point,
511
- ]
512
+ for (const point of mergedRoute) {
513
+ if (point.route_type === "via") {
514
+ db.pcb_via.insert({
515
+ x: point.x,
516
+ y: point.y,
517
+ hole_diameter: 0.3,
518
+ outer_diameter: 0.6,
519
+ layers: [point.from_layer as LayerRef, point.to_layer as LayerRef],
520
+ from_layer: point.from_layer as LayerRef,
521
+ to_layer: point.to_layer as LayerRef,
522
+ })
512
523
  }
513
- return [point]
514
- })
515
-
516
- for (const via of routeWithVias.filter((p) => p.route_type === "via")) {
517
- db.pcb_via.insert({
518
- x: via.x,
519
- y: via.y,
520
- hole_diameter: 0.3,
521
- outer_diameter: 0.6,
522
- layers: [via.from_layer as LayerRef, via.to_layer as LayerRef],
523
- from_layer: via.from_layer as LayerRef,
524
- to_layer: via.to_layer as LayerRef,
525
- })
526
524
  }
527
525
 
528
526
  const pcb_trace = db.pcb_trace.insert({
529
- route: routeWithVias,
527
+ route: mergedRoute,
530
528
  source_trace_id: this.source_trace_id!,
531
529
  })
532
530
  this._portsRoutedOnPcb = ports
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.59",
5
+ "version": "0.0.60",
6
6
  "types": "dist/index.d.ts",
7
7
  "main": "dist/index.js",
8
8
  "files": [