@tscircuit/capacity-autorouter 0.0.10 → 0.0.12

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.js CHANGED
@@ -1757,17 +1757,19 @@ var SingleHighDensityRouteSolver = class extends BaseSolver {
1757
1757
  }
1758
1758
  handleSimpleCases() {
1759
1759
  this.solved = true;
1760
+ const { A, B } = this;
1761
+ const route = A.z === B.z ? [A, B] : [
1762
+ A,
1763
+ { ...this.boundsCenter, z: this.A.z },
1764
+ {
1765
+ ...this.boundsCenter,
1766
+ z: B.z
1767
+ },
1768
+ B
1769
+ ];
1760
1770
  this.solvedPath = {
1761
1771
  connectionName: this.connectionName,
1762
- route: [
1763
- this.A,
1764
- { ...this.boundsCenter, z: this.A.z },
1765
- {
1766
- ...this.boundsCenter,
1767
- z: this.B.z
1768
- },
1769
- this.B
1770
- ],
1772
+ route,
1771
1773
  traceThickness: this.traceThickness,
1772
1774
  viaDiameter: this.viaDiameter,
1773
1775
  vias: this.A.z === this.B.z ? [] : [this.boundsCenter]
@@ -2210,8 +2212,8 @@ var getMinDistBetweenEnteringPoints = (node) => {
2210
2212
  return minDist === Infinity ? 0 : minDist;
2211
2213
  };
2212
2214
 
2213
- // lib/solvers/HighDensitySolver/SingleIntraNodeRouteSolver.ts
2214
- var SingleIntraNodeRouteSolver = class extends BaseSolver {
2215
+ // lib/solvers/HighDensitySolver/IntraNodeSolver.ts
2216
+ var IntraNodeRouteSolver = class extends BaseSolver {
2215
2217
  nodeWithPortPoints;
2216
2218
  colorMap;
2217
2219
  unsolvedConnections;
@@ -2303,6 +2305,15 @@ var SingleIntraNodeRouteSolver = class extends BaseSolver {
2303
2305
  this.solved = this.failedSolvers.length === 0;
2304
2306
  return;
2305
2307
  }
2308
+ if (unsolvedConnection.points.length === 1) {
2309
+ return;
2310
+ }
2311
+ if (unsolvedConnection.points.length === 2) {
2312
+ const [A, B] = unsolvedConnection.points;
2313
+ if (A.x === B.x && A.y === B.y && A.z === B.z) {
2314
+ return;
2315
+ }
2316
+ }
2306
2317
  const { connectionName, points } = unsolvedConnection;
2307
2318
  this.activeSolver = new SingleHighDensityRouteSolver6_VertHorzLayer_FutureCost({
2308
2319
  connectionName,
@@ -2598,7 +2609,7 @@ var HyperSingleIntraNodeSolver = class extends HyperParameterSupervisorSolver {
2598
2609
  return 1 - (solver.progress || 0);
2599
2610
  }
2600
2611
  generateSolver(hyperParameters) {
2601
- return new SingleIntraNodeRouteSolver({
2612
+ return new IntraNodeRouteSolver({
2602
2613
  ...this.constructorParams,
2603
2614
  hyperParameters
2604
2615
  });
@@ -2639,8 +2650,8 @@ function mergeRouteSegments(route, connectionName, color) {
2639
2650
  return segments;
2640
2651
  }
2641
2652
 
2642
- // lib/solvers/HighDensitySolver/HighDensityRouteSolver.ts
2643
- var HighDensityRouteSolver = class extends BaseSolver {
2653
+ // lib/solvers/HighDensitySolver/HighDensitySolver.ts
2654
+ var HighDensitySolver = class extends BaseSolver {
2644
2655
  unsolvedNodePortPoints;
2645
2656
  routes;
2646
2657
  colorMap;
@@ -4287,24 +4298,26 @@ var NetToPointPairsSolver = class extends BaseSolver {
4287
4298
  }
4288
4299
  };
4289
4300
 
4301
+ // lib/utils/mapZToLayerName.ts
4302
+ var mapZToLayerName = (z, layerCount) => {
4303
+ if (z < 0 || z >= layerCount) {
4304
+ throw new Error(`Invalid z "${z}" for layer count: ${layerCount}`);
4305
+ }
4306
+ if (z === 0) return "top";
4307
+ if (z === layerCount - 1) return "bottom";
4308
+ return `inner${z}`;
4309
+ };
4310
+
4290
4311
  // lib/utils/convertHdRouteToSimplifiedRoute.ts
4291
4312
  var convertHdRouteToSimplifiedRoute = (hdRoute, layerCount) => {
4292
4313
  const result = [];
4293
4314
  if (hdRoute.route.length === 0) return result;
4294
- const mapZToLayerName = (z) => {
4295
- if (z < 0 || z >= layerCount) {
4296
- throw new Error(`Invalid z "${z}" for layer count: ${layerCount}`);
4297
- }
4298
- if (z === 0) return "top";
4299
- if (z === layerCount - 1) return "bottom";
4300
- return `inner${z}`;
4301
- };
4302
4315
  let currentLayerPoints = [];
4303
4316
  let currentZ = hdRoute.route[0].z;
4304
4317
  for (let i = 0; i < hdRoute.route.length; i++) {
4305
4318
  const point = hdRoute.route[i];
4306
4319
  if (point.z !== currentZ) {
4307
- const layerName2 = mapZToLayerName(currentZ);
4320
+ const layerName2 = mapZToLayerName(currentZ, layerCount);
4308
4321
  for (const layerPoint of currentLayerPoints) {
4309
4322
  result.push({
4310
4323
  route_type: "wire",
@@ -4318,8 +4331,8 @@ var convertHdRouteToSimplifiedRoute = (hdRoute, layerCount) => {
4318
4331
  (via) => Math.abs(via.x - point.x) < 1e-3 && Math.abs(via.y - point.y) < 1e-3
4319
4332
  );
4320
4333
  if (viaExists) {
4321
- const fromLayer = mapZToLayerName(currentZ);
4322
- const toLayer = mapZToLayerName(point.z);
4334
+ const fromLayer = mapZToLayerName(currentZ, layerCount);
4335
+ const toLayer = mapZToLayerName(point.z, layerCount);
4323
4336
  result.push({
4324
4337
  route_type: "via",
4325
4338
  x: point.x,
@@ -4334,7 +4347,7 @@ var convertHdRouteToSimplifiedRoute = (hdRoute, layerCount) => {
4334
4347
  currentLayerPoints.push(point);
4335
4348
  }
4336
4349
  }
4337
- const layerName = mapZToLayerName(currentZ);
4350
+ const layerName = mapZToLayerName(currentZ, layerCount);
4338
4351
  for (const layerPoint of currentLayerPoints) {
4339
4352
  result.push({
4340
4353
  route_type: "wire",
@@ -4347,7 +4360,371 @@ var convertHdRouteToSimplifiedRoute = (hdRoute, layerCount) => {
4347
4360
  return result;
4348
4361
  };
4349
4362
 
4363
+ // lib/utils/mapLayerNameToZ.ts
4364
+ var mapLayerNameToZ = (layerName, layerCount) => {
4365
+ if (layerName === "top") return 0;
4366
+ if (layerName === "bottom") return layerCount - 1;
4367
+ return parseInt(layerName.slice(5));
4368
+ };
4369
+
4370
+ // lib/solvers/RouteStitchingSolver/SingleHighDensityRouteStitchSolver.ts
4371
+ var SingleHighDensityRouteStitchSolver = class extends BaseSolver {
4372
+ mergedHdRoute;
4373
+ remainingHdRoutes;
4374
+ start;
4375
+ end;
4376
+ constructor(opts) {
4377
+ super();
4378
+ this.remainingHdRoutes = [...opts.hdRoutes];
4379
+ this.mergedHdRoute = {
4380
+ connectionName: opts.hdRoutes[0].connectionName,
4381
+ route: [
4382
+ {
4383
+ x: opts.start.x,
4384
+ y: opts.start.y,
4385
+ z: opts.start.z
4386
+ }
4387
+ ],
4388
+ vias: [],
4389
+ viaDiameter: opts.hdRoutes[0].viaDiameter,
4390
+ traceThickness: opts.hdRoutes[0].traceThickness
4391
+ };
4392
+ this.start = opts.start;
4393
+ this.end = opts.end;
4394
+ }
4395
+ _step() {
4396
+ if (this.remainingHdRoutes.length === 0) {
4397
+ this.mergedHdRoute.route.push({
4398
+ x: this.end.x,
4399
+ y: this.end.y,
4400
+ z: this.end.z
4401
+ });
4402
+ this.solved = true;
4403
+ return;
4404
+ }
4405
+ const lastMergedPoint = this.mergedHdRoute.route[this.mergedHdRoute.route.length - 1];
4406
+ let closestRouteIndex = 0;
4407
+ let matchedOn = "first";
4408
+ let closestDistance = Infinity;
4409
+ for (let i = 0; i < this.remainingHdRoutes.length; i++) {
4410
+ const hdRoute = this.remainingHdRoutes[i];
4411
+ const lastPointInCandidate = hdRoute.route[hdRoute.route.length - 1];
4412
+ const firstPointInCandidate = hdRoute.route[0];
4413
+ const distToFirst = distance(lastMergedPoint, firstPointInCandidate);
4414
+ const distToLast = distance(lastMergedPoint, lastPointInCandidate);
4415
+ if (distToFirst < closestDistance) {
4416
+ closestDistance = distToFirst;
4417
+ closestRouteIndex = i;
4418
+ matchedOn = "first";
4419
+ }
4420
+ if (distToLast < closestDistance) {
4421
+ closestDistance = distToLast;
4422
+ closestRouteIndex = i;
4423
+ matchedOn = "last";
4424
+ }
4425
+ }
4426
+ const hdRouteToMerge = this.remainingHdRoutes[closestRouteIndex];
4427
+ this.remainingHdRoutes.splice(closestRouteIndex, 1);
4428
+ if (matchedOn === "first") {
4429
+ this.mergedHdRoute.route.push(...hdRouteToMerge.route);
4430
+ } else {
4431
+ this.mergedHdRoute.route.push(...[...hdRouteToMerge.route].reverse());
4432
+ }
4433
+ this.mergedHdRoute.vias.push(...hdRouteToMerge.vias);
4434
+ }
4435
+ visualize() {
4436
+ const graphics = {
4437
+ points: [],
4438
+ lines: [],
4439
+ circles: [],
4440
+ title: "Single High Density Route Stitch Solver"
4441
+ };
4442
+ graphics.points?.push(
4443
+ {
4444
+ x: this.start.x,
4445
+ y: this.start.y,
4446
+ color: "green",
4447
+ label: "Start"
4448
+ },
4449
+ {
4450
+ x: this.end.x,
4451
+ y: this.end.y,
4452
+ color: "red",
4453
+ label: "End"
4454
+ }
4455
+ );
4456
+ if (this.mergedHdRoute && this.mergedHdRoute.route.length > 1) {
4457
+ graphics.lines?.push({
4458
+ points: this.mergedHdRoute.route.map((point) => ({
4459
+ x: point.x,
4460
+ y: point.y
4461
+ })),
4462
+ strokeColor: "green"
4463
+ });
4464
+ for (const point of this.mergedHdRoute.route) {
4465
+ graphics.points?.push({
4466
+ x: point.x,
4467
+ y: point.y,
4468
+ color: "green"
4469
+ });
4470
+ }
4471
+ for (const via of this.mergedHdRoute.vias) {
4472
+ graphics.circles?.push({
4473
+ center: { x: via.x, y: via.y },
4474
+ radius: this.mergedHdRoute.viaDiameter / 2,
4475
+ fill: "green"
4476
+ });
4477
+ }
4478
+ }
4479
+ const colorList = Array.from(
4480
+ { length: this.remainingHdRoutes.length },
4481
+ (_, i) => `hsl(${i * 360 / this.remainingHdRoutes.length}, 100%, 50%)`
4482
+ );
4483
+ for (const [i, hdRoute] of this.remainingHdRoutes.entries()) {
4484
+ if (hdRoute.route.length > 1) {
4485
+ graphics.lines?.push({
4486
+ points: hdRoute.route.map((point) => ({ x: point.x, y: point.y })),
4487
+ strokeColor: colorList[i]
4488
+ });
4489
+ }
4490
+ for (let pi = 0; pi < hdRoute.route.length; pi++) {
4491
+ const point = hdRoute.route[pi];
4492
+ graphics.points?.push({
4493
+ x: point.x + (i % 2 - 0.5) / 500 + (pi % 8 - 4) / 1e3,
4494
+ y: point.y + (i % 2 - 0.5) / 500 + (pi % 8 - 4) / 1e3,
4495
+ color: colorList[i],
4496
+ label: `Route ${i} ${point === hdRoute.route[0] ? "First" : point === hdRoute.route[hdRoute.route.length - 1] ? "Last" : ""}`
4497
+ });
4498
+ }
4499
+ for (const via of hdRoute.vias) {
4500
+ graphics.circles?.push({
4501
+ center: { x: via.x, y: via.y },
4502
+ radius: hdRoute.viaDiameter / 2,
4503
+ fill: colorList[i]
4504
+ });
4505
+ }
4506
+ }
4507
+ return graphics;
4508
+ }
4509
+ };
4510
+
4511
+ // lib/solvers/RouteStitchingSolver/MultipleHighDensityRouteStitchSolver.ts
4512
+ var MultipleHighDensityRouteStitchSolver = class extends BaseSolver {
4513
+ unsolvedRoutes;
4514
+ activeSolver = null;
4515
+ mergedHdRoutes = [];
4516
+ constructor(opts) {
4517
+ super();
4518
+ this.unsolvedRoutes = opts.connections.map((c) => ({
4519
+ connectionName: c.name,
4520
+ hdRoutes: opts.hdRoutes.filter((r) => r.connectionName === c.name),
4521
+ start: {
4522
+ ...c.pointsToConnect[0],
4523
+ z: mapLayerNameToZ(c.pointsToConnect[0].layer, opts.layerCount)
4524
+ },
4525
+ end: {
4526
+ ...c.pointsToConnect[1],
4527
+ z: mapLayerNameToZ(c.pointsToConnect[1].layer, opts.layerCount)
4528
+ }
4529
+ }));
4530
+ }
4531
+ _step() {
4532
+ if (this.activeSolver) {
4533
+ this.activeSolver.step();
4534
+ if (this.activeSolver.solved) {
4535
+ this.mergedHdRoutes.push(this.activeSolver.mergedHdRoute);
4536
+ this.activeSolver = null;
4537
+ } else if (this.activeSolver.failed) {
4538
+ this.failed = true;
4539
+ this.error = this.activeSolver.error;
4540
+ }
4541
+ return;
4542
+ }
4543
+ const unsolvedRoute = this.unsolvedRoutes.pop();
4544
+ if (!unsolvedRoute) {
4545
+ this.solved = true;
4546
+ return;
4547
+ }
4548
+ this.activeSolver = new SingleHighDensityRouteStitchSolver({
4549
+ hdRoutes: unsolvedRoute.hdRoutes,
4550
+ start: unsolvedRoute.start,
4551
+ end: unsolvedRoute.end
4552
+ });
4553
+ }
4554
+ visualize() {
4555
+ const graphics = {
4556
+ points: [],
4557
+ lines: [],
4558
+ circles: [],
4559
+ title: "Multiple High Density Route Stitch Solver"
4560
+ };
4561
+ if (this.activeSolver) {
4562
+ const activeSolverGraphics = this.activeSolver.visualize();
4563
+ if (activeSolverGraphics.points?.length) {
4564
+ graphics.points?.push(...activeSolverGraphics.points);
4565
+ }
4566
+ if (activeSolverGraphics.lines?.length) {
4567
+ graphics.lines?.push(...activeSolverGraphics.lines);
4568
+ }
4569
+ if (activeSolverGraphics.circles?.length) {
4570
+ graphics.circles?.push(...activeSolverGraphics.circles);
4571
+ }
4572
+ if (activeSolverGraphics.rects?.length) {
4573
+ graphics.rects = activeSolverGraphics.rects;
4574
+ }
4575
+ }
4576
+ for (const [i, mergedRoute] of this.mergedHdRoutes.entries()) {
4577
+ const solvedColor = `hsl(120, 100%, ${40 + i * 10 % 40}%)`;
4578
+ if (mergedRoute.route.length > 1) {
4579
+ graphics.lines?.push({
4580
+ points: mergedRoute.route.map((point) => ({
4581
+ x: point.x,
4582
+ y: point.y
4583
+ })),
4584
+ strokeColor: solvedColor,
4585
+ strokeWidth: mergedRoute.traceThickness
4586
+ });
4587
+ }
4588
+ for (const point of mergedRoute.route) {
4589
+ graphics.points?.push({
4590
+ x: point.x,
4591
+ y: point.y,
4592
+ color: solvedColor
4593
+ });
4594
+ }
4595
+ for (const via of mergedRoute.vias) {
4596
+ graphics.circles?.push({
4597
+ center: { x: via.x, y: via.y },
4598
+ radius: mergedRoute.viaDiameter / 2,
4599
+ fill: solvedColor
4600
+ });
4601
+ }
4602
+ }
4603
+ const colorList = Array.from(
4604
+ { length: this.unsolvedRoutes.length },
4605
+ (_, i) => `hsl(${i * 360 / this.unsolvedRoutes.length}, 100%, 50%)`
4606
+ );
4607
+ for (const [i, unsolvedRoute] of this.unsolvedRoutes.entries()) {
4608
+ graphics.points?.push(
4609
+ {
4610
+ x: unsolvedRoute.start.x,
4611
+ y: unsolvedRoute.start.y,
4612
+ color: colorList[i],
4613
+ label: `${unsolvedRoute.connectionName} Start`
4614
+ },
4615
+ {
4616
+ x: unsolvedRoute.end.x,
4617
+ y: unsolvedRoute.end.y,
4618
+ color: colorList[i],
4619
+ label: `${unsolvedRoute.connectionName} End`
4620
+ }
4621
+ );
4622
+ graphics.lines?.push({
4623
+ points: [
4624
+ { x: unsolvedRoute.start.x, y: unsolvedRoute.start.y },
4625
+ { x: unsolvedRoute.end.x, y: unsolvedRoute.end.y }
4626
+ ],
4627
+ strokeColor: colorList[i],
4628
+ strokeDash: "2 2"
4629
+ });
4630
+ for (const hdRoute of unsolvedRoute.hdRoutes) {
4631
+ if (hdRoute.route.length > 1) {
4632
+ graphics.lines?.push({
4633
+ points: hdRoute.route.map((point) => ({ x: point.x, y: point.y })),
4634
+ strokeColor: safeTransparentize(colorList[i], 0.5),
4635
+ strokeDash: "10 5"
4636
+ });
4637
+ }
4638
+ for (const via of hdRoute.vias) {
4639
+ graphics.circles?.push({
4640
+ center: { x: via.x, y: via.y },
4641
+ radius: hdRoute.viaDiameter / 2,
4642
+ fill: colorList[i]
4643
+ });
4644
+ }
4645
+ }
4646
+ }
4647
+ return graphics;
4648
+ }
4649
+ };
4650
+
4651
+ // tests/fixtures/convertSrjToGraphicsObject.ts
4652
+ var convertSrjToGraphicsObject = (srj) => {
4653
+ const lines = [];
4654
+ const circles = [];
4655
+ const points = [];
4656
+ const colorMap = getColorMap(srj);
4657
+ if (srj.connections) {
4658
+ for (const connection of srj.connections) {
4659
+ for (const point of connection.pointsToConnect) {
4660
+ points.push({
4661
+ x: point.x,
4662
+ y: point.y,
4663
+ color: colorMap[connection.name],
4664
+ label: `${connection.name} (${point.layer})`
4665
+ });
4666
+ }
4667
+ }
4668
+ }
4669
+ if (srj.traces) {
4670
+ for (const trace of srj.traces) {
4671
+ for (let j = 0; j < trace.route.length - 1; j++) {
4672
+ const routePoint = trace.route[j];
4673
+ const nextRoutePoint = trace.route[j + 1];
4674
+ if (routePoint.route_type === "via") {
4675
+ circles.push({
4676
+ center: { x: routePoint.x, y: routePoint.y },
4677
+ radius: 0.3,
4678
+ // 0.6 via diameter
4679
+ fill: "blue",
4680
+ stroke: "none"
4681
+ });
4682
+ } else if (routePoint.route_type === "wire" && nextRoutePoint.route_type === "wire" && nextRoutePoint.layer === routePoint.layer) {
4683
+ lines.push({
4684
+ points: [
4685
+ { x: routePoint.x, y: routePoint.y },
4686
+ { x: nextRoutePoint.x, y: nextRoutePoint.y }
4687
+ ],
4688
+ strokeColor: safeTransparentize(
4689
+ {
4690
+ top: "red",
4691
+ bottom: "blue",
4692
+ inner1: "green",
4693
+ inner2: "yellow"
4694
+ }[routePoint.layer],
4695
+ 0.5
4696
+ )
4697
+ // For some reason this is too small, likely a graphics-debug bug
4698
+ // strokeWidth: 0.15,
4699
+ });
4700
+ }
4701
+ }
4702
+ }
4703
+ }
4704
+ return {
4705
+ rects: srj.obstacles.map(
4706
+ (o) => ({
4707
+ center: o.center,
4708
+ width: o.width,
4709
+ height: o.height,
4710
+ fill: "rgba(255,0,0,0.5)"
4711
+ })
4712
+ ),
4713
+ circles,
4714
+ lines,
4715
+ points
4716
+ };
4717
+ };
4718
+
4350
4719
  // lib/solvers/CapacityMeshSolver/CapacityMeshSolver.ts
4720
+ function definePipelineStep(solverName, solverClass, getConstructorParams, opts = {}) {
4721
+ return {
4722
+ solverName,
4723
+ solverClass,
4724
+ getConstructorParams,
4725
+ onSolved: opts.onSolved
4726
+ };
4727
+ }
4351
4728
  var CapacityMeshSolver = class extends BaseSolver {
4352
4729
  constructor(srj, opts = {}) {
4353
4730
  super();
@@ -4366,6 +4743,9 @@ var CapacityMeshSolver = class extends BaseSolver {
4366
4743
  }
4367
4744
  this.connMap = getConnectivityMapFromSimpleRouteJson(srj);
4368
4745
  this.colorMap = getColorMap(srj, this.connMap);
4746
+ this.startTimeOfPhase = {};
4747
+ this.endTimeOfPhase = {};
4748
+ this.timeSpentOnPhase = {};
4369
4749
  }
4370
4750
  netToPointPairsSolver;
4371
4751
  nodeSolver;
@@ -4377,13 +4757,131 @@ var CapacityMeshSolver = class extends BaseSolver {
4377
4757
  segmentToPointSolver;
4378
4758
  segmentToPointOptimizer;
4379
4759
  highDensityRouteSolver;
4760
+ highDensityStitchSolver;
4761
+ startTimeOfPhase;
4762
+ endTimeOfPhase;
4763
+ timeSpentOnPhase;
4380
4764
  activeSolver = null;
4381
4765
  connMap;
4766
+ srjWithPointPairs;
4767
+ pipelineDef = [
4768
+ definePipelineStep(
4769
+ "netToPointPairsSolver",
4770
+ NetToPointPairsSolver,
4771
+ (cms) => [cms.srj, cms.colorMap],
4772
+ {
4773
+ onSolved: (cms) => {
4774
+ cms.srjWithPointPairs = cms.netToPointPairsSolver?.getNewSimpleRouteJson();
4775
+ cms.colorMap = getColorMap(cms.srjWithPointPairs, this.connMap);
4776
+ cms.connMap = getConnectivityMapFromSimpleRouteJson(
4777
+ cms.srjWithPointPairs
4778
+ );
4779
+ }
4780
+ }
4781
+ ),
4782
+ definePipelineStep("nodeSolver", CapacityMeshNodeSolver, (cms) => [
4783
+ cms.netToPointPairsSolver?.getNewSimpleRouteJson() || cms.srj,
4784
+ cms.opts
4785
+ ]),
4786
+ definePipelineStep("nodeTargetMerger", CapacityNodeTargetMerger, (cms) => [
4787
+ cms.nodeSolver?.finishedNodes || [],
4788
+ cms.srj.obstacles,
4789
+ cms.connMap
4790
+ ]),
4791
+ definePipelineStep("edgeSolver", CapacityMeshEdgeSolver, (cms) => [
4792
+ cms.nodeTargetMerger?.newNodes || []
4793
+ ]),
4794
+ definePipelineStep(
4795
+ "pathingSolver",
4796
+ CapacityPathingSolver4_FlexibleNegativeCapacity,
4797
+ (cms) => [
4798
+ {
4799
+ simpleRouteJson: cms.srjWithPointPairs,
4800
+ nodes: cms.nodeTargetMerger?.newNodes || [],
4801
+ edges: cms.edgeSolver?.edges || [],
4802
+ colorMap: cms.colorMap,
4803
+ hyperParameters: {
4804
+ MAX_CAPACITY_FACTOR: 1
4805
+ }
4806
+ }
4807
+ ]
4808
+ ),
4809
+ definePipelineStep(
4810
+ "edgeToPortSegmentSolver",
4811
+ CapacityEdgeToPortSegmentSolver,
4812
+ (cms) => [
4813
+ {
4814
+ nodes: cms.nodeTargetMerger?.newNodes || [],
4815
+ edges: cms.edgeSolver?.edges || [],
4816
+ capacityPaths: cms.pathingSolver?.getCapacityPaths() || [],
4817
+ colorMap: cms.colorMap
4818
+ }
4819
+ ]
4820
+ ),
4821
+ definePipelineStep(
4822
+ "segmentToPointSolver",
4823
+ CapacitySegmentToPointSolver,
4824
+ (cms) => {
4825
+ const allSegments = [];
4826
+ if (cms.edgeToPortSegmentSolver?.nodePortSegments) {
4827
+ cms.edgeToPortSegmentSolver.nodePortSegments.forEach((segs) => {
4828
+ allSegments.push(...segs);
4829
+ });
4830
+ }
4831
+ return [
4832
+ {
4833
+ segments: allSegments,
4834
+ colorMap: cms.colorMap,
4835
+ nodes: cms.nodeTargetMerger?.newNodes || []
4836
+ }
4837
+ ];
4838
+ }
4839
+ ),
4840
+ definePipelineStep(
4841
+ "segmentToPointOptimizer",
4842
+ CapacitySegmentPointOptimizer,
4843
+ (cms) => [
4844
+ {
4845
+ assignedSegments: cms.segmentToPointSolver?.solvedSegments || [],
4846
+ colorMap: cms.colorMap,
4847
+ nodes: cms.nodeTargetMerger?.newNodes || []
4848
+ }
4849
+ ]
4850
+ ),
4851
+ definePipelineStep("highDensityRouteSolver", HighDensitySolver, (cms) => [
4852
+ {
4853
+ nodePortPoints: cms.segmentToPointOptimizer?.getNodesWithPortPoints() || [],
4854
+ colorMap: cms.colorMap,
4855
+ connMap: cms.connMap
4856
+ }
4857
+ ]),
4858
+ definePipelineStep(
4859
+ "highDensityStitchSolver",
4860
+ MultipleHighDensityRouteStitchSolver,
4861
+ (cms) => [
4862
+ {
4863
+ connections: cms.srjWithPointPairs.connections,
4864
+ hdRoutes: cms.highDensityRouteSolver.routes,
4865
+ layerCount: cms.srj.layerCount
4866
+ }
4867
+ ]
4868
+ )
4869
+ ];
4870
+ currentPipelineStepIndex = 0;
4382
4871
  _step() {
4872
+ const pipelineStepDef = this.pipelineDef[this.currentPipelineStepIndex];
4873
+ if (!pipelineStepDef) {
4874
+ this.solved = true;
4875
+ return;
4876
+ }
4383
4877
  if (this.activeSolver) {
4384
4878
  this.activeSolver.step();
4385
4879
  if (this.activeSolver.solved) {
4880
+ this.endTimeOfPhase[pipelineStepDef.solverName] = performance.now();
4881
+ this.timeSpentOnPhase[pipelineStepDef.solverName] = this.endTimeOfPhase[pipelineStepDef.solverName] - this.startTimeOfPhase[pipelineStepDef.solverName];
4882
+ pipelineStepDef.onSolved?.(this);
4386
4883
  this.activeSolver = null;
4884
+ this.currentPipelineStepIndex++;
4387
4885
  } else if (this.activeSolver.failed) {
4388
4886
  this.error = this.activeSolver?.error;
4389
4887
  this.failed = true;
@@ -4391,93 +4889,16 @@ var CapacityMeshSolver = class extends BaseSolver {
4391
4889
  }
4392
4890
  return;
4393
4891
  }
4394
- if (!this.netToPointPairsSolver) {
4395
- this.netToPointPairsSolver = new NetToPointPairsSolver(
4396
- this.srj,
4397
- this.colorMap
4398
- );
4399
- this.activeSolver = this.netToPointPairsSolver;
4400
- return;
4401
- }
4402
- if (!this.nodeSolver) {
4403
- const newSrj = this.netToPointPairsSolver.getNewSimpleRouteJson();
4404
- this.connMap = getConnectivityMapFromSimpleRouteJson(newSrj);
4405
- this.colorMap = getColorMap(newSrj, this.connMap);
4406
- this.nodeSolver = new CapacityMeshNodeSolver(newSrj, this.opts);
4407
- this.activeSolver = this.nodeSolver;
4408
- return;
4409
- }
4410
- if (!this.nodeTargetMerger) {
4411
- this.nodeTargetMerger = new CapacityNodeTargetMerger(
4412
- this.nodeSolver.finishedNodes,
4413
- this.srj.obstacles,
4414
- this.connMap
4415
- );
4416
- this.activeSolver = this.nodeTargetMerger;
4417
- return;
4418
- }
4419
- const nodes = this.nodeTargetMerger.newNodes;
4420
- if (!this.edgeSolver) {
4421
- this.edgeSolver = new CapacityMeshEdgeSolver(nodes);
4422
- this.activeSolver = this.edgeSolver;
4423
- return;
4424
- }
4425
- if (!this.pathingSolver) {
4426
- this.pathingSolver = new CapacityPathingSolver4_FlexibleNegativeCapacity({
4427
- simpleRouteJson: this.netToPointPairsSolver.getNewSimpleRouteJson(),
4428
- nodes,
4429
- edges: this.edgeSolver.edges,
4430
- colorMap: this.colorMap,
4431
- hyperParameters: {
4432
- MAX_CAPACITY_FACTOR: 1
4433
- }
4434
- });
4435
- this.activeSolver = this.pathingSolver;
4436
- return;
4437
- }
4438
- if (!this.edgeToPortSegmentSolver) {
4439
- this.edgeToPortSegmentSolver = new CapacityEdgeToPortSegmentSolver({
4440
- nodes,
4441
- edges: this.edgeSolver.edges,
4442
- capacityPaths: this.pathingSolver.getCapacityPaths(),
4443
- colorMap: this.colorMap
4444
- });
4445
- this.activeSolver = this.edgeToPortSegmentSolver;
4446
- return;
4447
- }
4448
- if (!this.segmentToPointSolver) {
4449
- const allSegments = [];
4450
- this.edgeToPortSegmentSolver.nodePortSegments.forEach((segs) => {
4451
- allSegments.push(...segs);
4452
- });
4453
- this.segmentToPointSolver = new CapacitySegmentToPointSolver({
4454
- segments: allSegments,
4455
- colorMap: this.colorMap,
4456
- nodes
4457
- });
4458
- this.activeSolver = this.segmentToPointSolver;
4459
- return;
4460
- }
4461
- if (!this.segmentToPointOptimizer) {
4462
- this.segmentToPointOptimizer = new CapacitySegmentPointOptimizer({
4463
- assignedSegments: this.segmentToPointSolver.solvedSegments,
4464
- colorMap: this.colorMap,
4465
- nodes
4466
- });
4467
- this.activeSolver = this.segmentToPointOptimizer;
4468
- return;
4469
- }
4470
- if (!this.highDensityRouteSolver) {
4471
- const nodesWithPortPoints = this.segmentToPointOptimizer.getNodesWithPortPoints();
4472
- this.highDensityRouteSolver = new HighDensityRouteSolver({
4473
- nodePortPoints: nodesWithPortPoints,
4474
- colorMap: this.colorMap,
4475
- connMap: this.connMap
4476
- });
4477
- this.activeSolver = this.highDensityRouteSolver;
4478
- return;
4479
- }
4480
- this.solved = true;
4892
+ const constructorParams = pipelineStepDef.getConstructorParams(this);
4893
+ this.activeSolver = new pipelineStepDef.solverClass(
4894
+ ...constructorParams
4895
+ );
4896
+ this[pipelineStepDef.solverName] = this.activeSolver;
4897
+ this.timeSpentOnPhase[pipelineStepDef.solverName] = 0;
4898
+ this.startTimeOfPhase[pipelineStepDef.solverName] = performance.now();
4899
+ }
4900
+ getCurrentPhase() {
4901
+ return this.pipelineDef[this.currentPipelineStepIndex]?.solverName ?? "none";
4481
4902
  }
4482
4903
  visualize() {
4483
4904
  if (!this.solved && this.activeSolver) return this.activeSolver.visualize();
@@ -4489,6 +4910,7 @@ var CapacityMeshSolver = class extends BaseSolver {
4489
4910
  const segmentToPointViz = this.segmentToPointSolver?.visualize();
4490
4911
  const segmentOptimizationViz = this.segmentToPointOptimizer?.visualize();
4491
4912
  const highDensityViz = this.highDensityRouteSolver?.visualize();
4913
+ const highDensityStitchViz = this.highDensityStitchSolver?.visualize();
4492
4914
  const problemViz = {
4493
4915
  points: [...this.srj.connections.flatMap((c) => c.pointsToConnect)],
4494
4916
  rects: [
@@ -4507,51 +4929,15 @@ var CapacityMeshSolver = class extends BaseSolver {
4507
4929
  edgeToPortSegmentViz,
4508
4930
  segmentToPointViz,
4509
4931
  segmentOptimizationViz,
4510
- highDensityViz ? combineVisualizations(problemViz, highDensityViz) : null
4932
+ highDensityViz ? combineVisualizations(problemViz, highDensityViz) : null,
4933
+ highDensityStitchViz,
4934
+ this.solved ? combineVisualizations(
4935
+ problemViz,
4936
+ convertSrjToGraphicsObject(this.getOutputSimpleRouteJson())
4937
+ ) : null
4511
4938
  ].filter(Boolean);
4512
4939
  return combineVisualizations(...visualizations);
4513
4940
  }
4514
- /**
4515
- * Simplifies a route by merging consecutive points along the same line
4516
- */
4517
- simplifyRoute(points) {
4518
- if (points.length <= 2) return points;
4519
- const result = [points[0]];
4520
- for (let i = 1; i < points.length - 1; i++) {
4521
- const prev = points[i - 1];
4522
- const curr = points[i];
4523
- const next = points[i + 1];
4524
- if (curr.z === prev.z && curr.z === next.z) {
4525
- const dx1 = curr.x - prev.x;
4526
- const dy1 = curr.y - prev.y;
4527
- const dx2 = next.x - curr.x;
4528
- const dy2 = next.y - curr.y;
4529
- const crossProduct = dx1 * dy2 - dy1 * dx2;
4530
- const dotProduct = dx1 * dx2 + dy1 * dy2;
4531
- if (Math.abs(crossProduct) < 1e-3 && dotProduct > 0) {
4532
- continue;
4533
- }
4534
- }
4535
- result.push(curr);
4536
- }
4537
- result.push(points[points.length - 1]);
4538
- return result;
4539
- }
4540
- /**
4541
- * Maps numeric layer to named layer
4542
- * @param layer Numeric layer (0, 1, etc)
4543
- * @returns Named layer ("top", "bottom", etc)
4544
- */
4545
- mapLayer(layer) {
4546
- switch (layer) {
4547
- case "0":
4548
- return "top";
4549
- case "1":
4550
- return "bottom";
4551
- default:
4552
- return `layer${layer}`;
4553
- }
4554
- }
4555
4941
  /**
4556
4942
  * Get original connection name from connection name with MST suffix
4557
4943
  * @param mstConnectionName The MST-suffixed connection name (e.g. "connection1_mst0")
@@ -4564,24 +4950,38 @@ var CapacityMeshSolver = class extends BaseSolver {
4564
4950
  /**
4565
4951
  * Returns the SimpleRouteJson with routes converted to SimplifiedPcbTraces
4566
4952
  */
4567
- getOutputSimpleRouteJson() {
4953
+ getOutputSimplifiedPcbTraces() {
4568
4954
  if (!this.solved || !this.highDensityRouteSolver) {
4569
4955
  throw new Error("Cannot get output before solving is complete");
4570
4956
  }
4571
4957
  const traces = [];
4572
- for (const hdRoute of this.highDensityRouteSolver.routes) {
4573
- const pointPairConnName = hdRoute.connectionName;
4574
- const trace = {
4958
+ for (const connection of this.netToPointPairsSolver?.newConnections ?? []) {
4959
+ const netConnection = this.srj.connections.find(
4960
+ (c) => c.name === connection.netConnectionName
4961
+ );
4962
+ const hdRoutes = this.highDensityStitchSolver.mergedHdRoutes.filter(
4963
+ (r) => r.connectionName === connection.name
4964
+ );
4965
+ if (hdRoutes.length > 1) {
4966
+ throw new Error("Multiple hdRoutes found for connection");
4967
+ }
4968
+ const simplifiedPcbTrace = {
4575
4969
  type: "pcb_trace",
4576
- pcb_trace_id: pointPairConnName,
4577
- connection_name: this.getOriginalConnectionName(pointPairConnName),
4578
- route: convertHdRouteToSimplifiedRoute(hdRoute, 2)
4970
+ pcb_trace_id: connection.name,
4971
+ connection_name: this.getOriginalConnectionName(connection.name),
4972
+ route: convertHdRouteToSimplifiedRoute(
4973
+ hdRoutes[0],
4974
+ this.srj.layerCount
4975
+ )
4579
4976
  };
4580
- traces.push(trace);
4977
+ traces.push(simplifiedPcbTrace);
4581
4978
  }
4979
+ return traces;
4980
+ }
4981
+ getOutputSimpleRouteJson() {
4582
4982
  return {
4583
4983
  ...this.srj,
4584
- traces
4984
+ traces: this.getOutputSimplifiedPcbTraces()
4585
4985
  };
4586
4986
  }
4587
4987
  };