@tscircuit/copper-pour-solver 0.0.19 → 0.0.21

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
@@ -1,6 +1,6 @@
1
1
  import { BasePipelineSolver } from '@tscircuit/solver-utils';
2
2
  import { Bounds, Point } from '@tscircuit/math-utils';
3
- import { BRepShape, AnyCircuitElement, LayerRef } from 'circuit-json';
3
+ import { BRepShape, AnyCircuitElement, LayerRef, Point as Point$1 } from 'circuit-json';
4
4
 
5
5
  interface InputPourRegion {
6
6
  shape: "rect";
@@ -61,6 +61,7 @@ declare const convertCircuitJsonToInputProblem: (circuitJson: AnyCircuitElement[
61
61
  trace_margin: number;
62
62
  board_edge_margin?: number;
63
63
  cutout_margin?: number;
64
+ outline?: Point$1[];
64
65
  }) => InputProblem;
65
66
 
66
67
  export { type BaseInputPad, CopperPourPipelineSolver, type InputCircularPad, type InputPad, type InputPolygonPad, type InputPourRegion, type InputProblem, type InputRectPad, type InputTracePad, type PipelineOutput, convertCircuitJsonToInputProblem };
package/dist/index.js CHANGED
@@ -237,7 +237,6 @@ var processObstaclesForPour = (pads, pourConnectivityKey, margins, boardOutline)
237
237
  )
238
238
  );
239
239
  }
240
- continue;
241
240
  }
242
241
  }
243
242
  return { polygonsToSubtract };
@@ -294,6 +293,7 @@ var CopperPourPipelineSolver = class extends BasePipelineSolver {
294
293
  super(input);
295
294
  this.input = input;
296
295
  }
296
+ input;
297
297
  pipelineDef = [];
298
298
  getSolverName() {
299
299
  return "CopperPourPipelineSolver";
@@ -385,7 +385,6 @@ var convertCircuitJsonToInputProblem = (circuitJson, options) => {
385
385
  }
386
386
  } else if (elm.type === "pcb_plated_hole") {
387
387
  const platedHole = elm;
388
- if (platedHole.shape !== "circle") continue;
389
388
  if (!platedHole.layers.includes(options.layer)) continue;
390
389
  let connectivityKey = connectivityMap.getNetConnectedToId(
391
390
  platedHole.pcb_plated_hole_id
@@ -393,15 +392,35 @@ var convertCircuitJsonToInputProblem = (circuitJson, options) => {
393
392
  if (!connectivityKey) {
394
393
  connectivityKey = `unconnected-plated-hole:${platedHole.pcb_plated_hole_id}`;
395
394
  }
396
- pads.push({
397
- shape: "circle",
398
- padId: platedHole.pcb_plated_hole_id,
399
- layer: options.layer,
400
- connectivityKey,
401
- x: platedHole.x,
402
- y: platedHole.y,
403
- radius: platedHole.outer_diameter / 2
404
- });
395
+ if (platedHole.shape === "circle") {
396
+ pads.push({
397
+ shape: "circle",
398
+ padId: platedHole.pcb_plated_hole_id,
399
+ layer: options.layer,
400
+ connectivityKey,
401
+ x: platedHole.x,
402
+ y: platedHole.y,
403
+ radius: platedHole.outer_diameter / 2
404
+ });
405
+ } else if (platedHole.shape === "circular_hole_with_rect_pad") {
406
+ const rectWidth = platedHole.rect_pad_width;
407
+ const rectHeight = platedHole.rect_pad_height;
408
+ if (typeof rectWidth !== "number" || typeof rectHeight !== "number") {
409
+ continue;
410
+ }
411
+ pads.push({
412
+ shape: "rect",
413
+ padId: platedHole.pcb_plated_hole_id,
414
+ layer: options.layer,
415
+ connectivityKey,
416
+ bounds: {
417
+ minX: platedHole.x - rectWidth / 2,
418
+ minY: platedHole.y - rectHeight / 2,
419
+ maxX: platedHole.x + rectWidth / 2,
420
+ maxY: platedHole.y + rectHeight / 2
421
+ }
422
+ });
423
+ }
405
424
  } else if (elm.type === "pcb_hole") {
406
425
  const hole = elm;
407
426
  if (hole.hole_shape !== "circle") continue;
@@ -501,17 +520,31 @@ var convertCircuitJsonToInputProblem = (circuitJson, options) => {
501
520
  }
502
521
  }
503
522
  const { width, height } = pcb_board;
523
+ const outline = options.outline ?? pcb_board.outline;
524
+ let bounds;
525
+ if (outline && outline.length > 0) {
526
+ const xs = outline.map((p) => p.x);
527
+ const ys = outline.map((p) => p.y);
528
+ bounds = {
529
+ minX: Math.min(...xs),
530
+ minY: Math.min(...ys),
531
+ maxX: Math.max(...xs),
532
+ maxY: Math.max(...ys)
533
+ };
534
+ } else {
535
+ bounds = {
536
+ minX: -width / 2,
537
+ minY: -height / 2,
538
+ maxX: width / 2,
539
+ maxY: height / 2
540
+ };
541
+ }
504
542
  const regionsForPour = [
505
543
  {
506
544
  shape: "rect",
507
545
  layer: options.layer,
508
- bounds: {
509
- minX: -width / 2,
510
- minY: -height / 2,
511
- maxX: width / 2,
512
- maxY: height / 2
513
- },
514
- outline: pcb_board.outline,
546
+ bounds,
547
+ outline,
515
548
  connectivityKey: options.pour_connectivity_key,
516
549
  padMargin: options.pad_margin,
517
550
  traceMargin: options.trace_margin,
@@ -32,6 +32,7 @@ export const convertCircuitJsonToInputProblem = (
32
32
  trace_margin: number
33
33
  board_edge_margin?: number
34
34
  cutout_margin?: number
35
+ outline?: Point[]
35
36
  },
36
37
  ): InputProblem => {
37
38
  const pcb_board = circuitJson.find((e) => e.type === "pcb_board") as
@@ -83,7 +84,6 @@ export const convertCircuitJsonToInputProblem = (
83
84
  }
84
85
  } else if (elm.type === "pcb_plated_hole") {
85
86
  const platedHole = elm as PcbPlatedHole
86
- if (platedHole.shape !== "circle") continue
87
87
  if (!platedHole.layers.includes(options.layer)) continue
88
88
 
89
89
  let connectivityKey = connectivityMap.getNetConnectedToId(
@@ -93,15 +93,35 @@ export const convertCircuitJsonToInputProblem = (
93
93
  connectivityKey = `unconnected-plated-hole:${platedHole.pcb_plated_hole_id}`
94
94
  }
95
95
 
96
- pads.push({
97
- shape: "circle",
98
- padId: platedHole.pcb_plated_hole_id,
99
- layer: options.layer,
100
- connectivityKey,
101
- x: platedHole.x,
102
- y: platedHole.y,
103
- radius: platedHole.outer_diameter / 2,
104
- } as InputCircularPad)
96
+ if (platedHole.shape === "circle") {
97
+ pads.push({
98
+ shape: "circle",
99
+ padId: platedHole.pcb_plated_hole_id,
100
+ layer: options.layer,
101
+ connectivityKey,
102
+ x: platedHole.x,
103
+ y: platedHole.y,
104
+ radius: platedHole.outer_diameter / 2,
105
+ } as InputCircularPad)
106
+ } else if (platedHole.shape === "circular_hole_with_rect_pad") {
107
+ const rectWidth = (platedHole as any).rect_pad_width
108
+ const rectHeight = (platedHole as any).rect_pad_height
109
+ if (typeof rectWidth !== "number" || typeof rectHeight !== "number") {
110
+ continue
111
+ }
112
+ pads.push({
113
+ shape: "rect",
114
+ padId: platedHole.pcb_plated_hole_id,
115
+ layer: options.layer,
116
+ connectivityKey,
117
+ bounds: {
118
+ minX: platedHole.x - rectWidth / 2,
119
+ minY: platedHole.y - rectHeight / 2,
120
+ maxX: platedHole.x + rectWidth / 2,
121
+ maxY: platedHole.y + rectHeight / 2,
122
+ },
123
+ } as InputRectPad)
124
+ }
105
125
  } else if (elm.type === "pcb_hole") {
106
126
  const hole = elm as PcbHole
107
127
  if (hole.hole_shape !== "circle") continue
@@ -207,17 +227,35 @@ export const convertCircuitJsonToInputProblem = (
207
227
  }
208
228
 
209
229
  const { width, height } = pcb_board
230
+
231
+ // Use pour-specific outline if provided, otherwise fall back to board outline
232
+ const outline = options.outline ?? pcb_board.outline
233
+
234
+ let bounds: { minX: number; minY: number; maxX: number; maxY: number }
235
+ if (outline && outline.length > 0) {
236
+ const xs = outline.map((p) => p.x)
237
+ const ys = outline.map((p) => p.y)
238
+ bounds = {
239
+ minX: Math.min(...xs),
240
+ minY: Math.min(...ys),
241
+ maxX: Math.max(...xs),
242
+ maxY: Math.max(...ys),
243
+ }
244
+ } else {
245
+ bounds = {
246
+ minX: -width! / 2,
247
+ minY: -height! / 2,
248
+ maxX: width! / 2,
249
+ maxY: height! / 2,
250
+ }
251
+ }
252
+
210
253
  const regionsForPour = [
211
254
  {
212
255
  shape: "rect" as const,
213
256
  layer: options.layer,
214
- bounds: {
215
- minX: -width! / 2,
216
- minY: -height! / 2,
217
- maxX: width! / 2,
218
- maxY: height! / 2,
219
- },
220
- outline: pcb_board.outline,
257
+ bounds,
258
+ outline,
221
259
  connectivityKey: options.pour_connectivity_key,
222
260
  padMargin: options.pad_margin,
223
261
  traceMargin: options.trace_margin,
@@ -271,7 +271,6 @@ export const processObstaclesForPour = (
271
271
  ),
272
272
  )
273
273
  }
274
- continue
275
274
  }
276
275
  }
277
276
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tscircuit/copper-pour-solver",
3
3
  "main": "dist/index.js",
4
- "version": "0.0.19",
4
+ "version": "0.0.21",
5
5
  "scripts": {
6
6
  "format": "biome format . --write",
7
7
  "format:check": "biome format .",
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="800" height="600" data-software-used-string="@tscircuit/core@0.0.985"><style></style><rect class="boundary" x="0" y="0" fill="#000" width="800" height="600" data-type="pcb_background" data-pcb-layer="global"/><rect class="pcb-boundary" fill="none" stroke="#fff" stroke-width="0.3" x="150" y="50" width="500" height="500" data-type="pcb_boundary" data-pcb-layer="global"/><path class="pcb-board" d="M 150 550 L 650 550 L 650 50 L 150 50 Z" fill="none" stroke="rgba(255, 255, 255, 0.5)" stroke-width="5" data-type="pcb_board" data-pcb-layer="board"/><rect class="pcb-pad" fill="rgb(200, 52, 52)" x="463.75" y="276.25" width="40" height="47.5" data-type="pcb_smtpad" data-pcb-layer="top"/><rect class="pcb-pad" fill="rgb(200, 52, 52)" x="546.25" y="276.25" width="40" height="47.5" data-type="pcb_smtpad" data-pcb-layer="top"/><rect class="pcb-pad" fill="rgb(200, 52, 52)" x="213.75" y="276.25" width="40" height="47.5" data-type="pcb_smtpad" data-pcb-layer="top"/><rect class="pcb-pad" fill="rgb(200, 52, 52)" x="296.25" y="276.25" width="40" height="47.5" data-type="pcb_smtpad" data-pcb-layer="top"/><path class="pcb-trace" stroke="rgb(200, 52, 52)" fill="none" d="M 316.25 300 L 483.75 300" stroke-width="7.5" stroke-linecap="round" stroke-linejoin="round" shape-rendering="crispEdges" data-type="pcb_trace" data-pcb-layer="top"/><path class="pcb-trace" stroke="rgb(200, 52, 52)" fill="none" d="M 483.75 300 L 483.75 300" stroke-width="7.5" stroke-linecap="round" stroke-linejoin="round" shape-rendering="crispEdges" data-type="pcb_trace" data-pcb-layer="top"/><path class="pcb-copper-pour pcb-copper-pour-brep" d="M 382.75 313.75 L 400 400 L 250 500 L 200 550 L 150 550 L 150 450 L 150 150 L 350 150 L 377.25 286.25 L 346.25 286.25 L 346.25 266.25 L 286.25 266.25 L 286.25 333.75 L 346.25 333.75 L 346.25 313.75 L 382.75 313.75 Z" fill="rgb(200, 52, 52)" fill-rule="evenodd" fill-opacity="0.5" data-type="pcb_copper_pour" data-pcb-layer="top"/><path class="pcb-copper-pour pcb-copper-pour-brep" d="M 550 550 L 550 500 L 400 400 L 450 150 L 650 150 L 650 550 L 550 550 Z M 536.25 333.75 L 596.25 333.75 L 596.25 266.25 L 536.25 266.25 L 536.25 333.75 Z" fill="rgb(200, 52, 52)" fill-rule="evenodd" fill-opacity="0.5" data-type="pcb_copper_pour" data-pcb-layer="top"/><path class="pcb-silkscreen pcb-silkscreen-top" d="M 566.25 256.25 L 453.75 256.25 L 453.75 343.75 L 566.25 343.75" fill="none" stroke="#f2eda1" stroke-width="5" stroke-linecap="round" stroke-linejoin="round" data-pcb-component-id="pcb_component_0" data-pcb-silkscreen-path-id="pcb_silkscreen_path_0" data-type="pcb_silkscreen_path" data-pcb-layer="top"/><text x="0" y="0" dx="0" dy="0" fill="#f2eda1" font-family="Arial, sans-serif" font-size="20" text-anchor="middle" dominant-baseline="central" transform="matrix(1,0,0,1,525,231.25)" class="pcb-silkscreen-text pcb-silkscreen-top" data-pcb-silkscreen-text-id="pcb_component_0" stroke="none" data-type="pcb_silkscreen_text" data-pcb-layer="top">R1</text><path class="pcb-silkscreen pcb-silkscreen-top" d="M 316.25 256.25 L 203.75 256.25 L 203.75 343.75 L 316.25 343.75" fill="none" stroke="#f2eda1" stroke-width="5" stroke-linecap="round" stroke-linejoin="round" data-pcb-component-id="pcb_component_1" data-pcb-silkscreen-path-id="pcb_silkscreen_path_1" data-type="pcb_silkscreen_path" data-pcb-layer="top"/><text x="0" y="0" dx="0" dy="0" fill="#f2eda1" font-family="Arial, sans-serif" font-size="20" text-anchor="middle" dominant-baseline="central" transform="matrix(1,0,0,1,275,231.25)" class="pcb-silkscreen-text pcb-silkscreen-top" data-pcb-silkscreen-text-id="pcb_component_1" stroke="none" data-type="pcb_silkscreen_text" data-pcb-layer="top">C1</text></svg>