@tscircuit/hypergraph 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.
Files changed (3) hide show
  1. package/dist/index.d.ts +172 -56
  2. package/dist/index.js +874 -752
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -3490,700 +3490,321 @@ ${errors.map((e) => ` - ${e}`).join("\n")}`
3490
3490
  }
3491
3491
  };
3492
3492
 
3493
- // lib/ViaGraphSolver/polygonPerimeterUtils.ts
3494
- function polygonPerimeterT(p, polygon) {
3495
- const n = polygon.length;
3496
- let bestDist = Infinity;
3497
- let bestEdgeIndex = 0;
3498
- let bestT = 0;
3499
- for (let i = 0; i < n; i++) {
3500
- const a2 = polygon[i];
3501
- const b2 = polygon[(i + 1) % n];
3502
- const dx = b2.x - a2.x;
3503
- const dy = b2.y - a2.y;
3504
- const lenSq = dx * dx + dy * dy;
3505
- if (lenSq < 1e-10) continue;
3506
- const t = Math.max(
3507
- 0,
3508
- Math.min(1, ((p.x - a2.x) * dx + (p.y - a2.y) * dy) / lenSq)
3509
- );
3510
- const projX = a2.x + t * dx;
3511
- const projY = a2.y + t * dy;
3512
- const dist = Math.sqrt((p.x - projX) ** 2 + (p.y - projY) ** 2);
3513
- if (dist < bestDist) {
3514
- bestDist = dist;
3515
- bestEdgeIndex = i;
3516
- bestT = t;
3493
+ // assets/ViaGraphSolver/vias-by-net.json
3494
+ var vias_by_net_default = {
3495
+ Net6: [
3496
+ {
3497
+ viaId: "4ef04070-bacf-4a8a-8ac9-ea222cf4bf2c",
3498
+ diameter: 0.6,
3499
+ position: {
3500
+ x: 1.483834,
3501
+ y: 0.582296
3502
+ }
3503
+ },
3504
+ {
3505
+ viaId: "79364d38-c966-4eff-aa4a-e3ff6cca6339",
3506
+ diameter: 0.6,
3507
+ position: {
3508
+ x: -0.8,
3509
+ y: -1.893395
3510
+ }
3511
+ },
3512
+ {
3513
+ viaId: "f1d52fd5-ddd2-4440-8772-da3d096b033f",
3514
+ diameter: 0.6,
3515
+ position: {
3516
+ x: -0.703066,
3517
+ y: 1.2
3518
+ }
3517
3519
  }
3518
- }
3519
- let cumulative = 0;
3520
- for (let i = 0; i < bestEdgeIndex; i++) {
3521
- const a2 = polygon[i];
3522
- const b2 = polygon[(i + 1) % n];
3523
- cumulative += Math.sqrt((b2.x - a2.x) ** 2 + (b2.y - a2.y) ** 2);
3524
- }
3525
- const a = polygon[bestEdgeIndex];
3526
- const b = polygon[(bestEdgeIndex + 1) % n];
3527
- const edgeLen = Math.sqrt((b.x - a.x) ** 2 + (b.y - a.y) ** 2);
3528
- cumulative += bestT * edgeLen;
3529
- return cumulative;
3530
- }
3531
- function computeDifferentNetCrossingsForPolygon(region, port1, port2) {
3532
- const polygon = region.d.polygon;
3533
- if (!polygon || polygon.length < 3) {
3534
- return 0;
3535
- }
3536
- const t1 = polygonPerimeterT(port1.d, polygon);
3537
- const t2 = polygonPerimeterT(port2.d, polygon);
3538
- const newChord = [t1, t2];
3539
- let crossings = 0;
3540
- const assignments = region.assignments ?? [];
3541
- for (const assignment of assignments) {
3542
- const existingT1 = polygonPerimeterT(
3543
- assignment.regionPort1.d,
3544
- polygon
3545
- );
3546
- const existingT2 = polygonPerimeterT(
3547
- assignment.regionPort2.d,
3548
- polygon
3549
- );
3550
- const existingChord = [existingT1, existingT2];
3551
- if (chordsCross(newChord, existingChord)) {
3552
- crossings++;
3520
+ ],
3521
+ Net5: [
3522
+ {
3523
+ viaId: "4e57cee8-0910-4c83-9ec1-1ed2c9d16dcc",
3524
+ diameter: 0.6,
3525
+ position: {
3526
+ x: 1.268717,
3527
+ y: -1.698536
3528
+ }
3529
+ },
3530
+ {
3531
+ viaId: "a3797f13-73f9-48c3-a448-bea3980cdd65",
3532
+ diameter: 0.6,
3533
+ position: {
3534
+ x: -1.115754,
3535
+ y: -0.799377
3536
+ }
3537
+ },
3538
+ {
3539
+ viaId: "b0c56bb1-ea80-4154-9bb7-cb0fd760de8f",
3540
+ diameter: 0.6,
3541
+ position: {
3542
+ x: 0.397934,
3543
+ y: 1.458567
3544
+ }
3553
3545
  }
3554
- }
3555
- return crossings;
3556
- }
3557
- function computeCrossingAssignmentsForPolygon(region, port1, port2) {
3558
- const polygon = region.d.polygon;
3559
- if (!polygon || polygon.length < 3) {
3560
- return [];
3561
- }
3562
- const t1 = polygonPerimeterT(port1.d, polygon);
3563
- const t2 = polygonPerimeterT(port2.d, polygon);
3564
- const newChord = [t1, t2];
3565
- const crossingAssignments = [];
3566
- const assignments = region.assignments ?? [];
3567
- for (const assignment of assignments) {
3568
- const existingT1 = polygonPerimeterT(
3569
- assignment.regionPort1.d,
3570
- polygon
3571
- );
3572
- const existingT2 = polygonPerimeterT(
3573
- assignment.regionPort2.d,
3574
- polygon
3575
- );
3576
- const existingChord = [existingT1, existingT2];
3577
- if (chordsCross(newChord, existingChord)) {
3578
- crossingAssignments.push(assignment);
3546
+ ],
3547
+ Net7: [
3548
+ {
3549
+ viaId: "3719876b-17c8-4ee3-9cce-5b5c073d6614",
3550
+ diameter: 0.6,
3551
+ position: {
3552
+ x: 1.186721,
3553
+ y: 1.32508
3554
+ }
3555
+ },
3556
+ {
3557
+ viaId: "4e46d759-a04a-4f7e-99cd-9e05adf5fa23",
3558
+ diameter: 0.6,
3559
+ position: {
3560
+ x: -1.275,
3561
+ y: 0
3562
+ }
3563
+ },
3564
+ {
3565
+ viaId: "63afce65-b94e-47da-ae14-51ff0ee8eb39",
3566
+ diameter: 0.6,
3567
+ position: {
3568
+ x: 1.655408,
3569
+ y: -0.998198
3570
+ }
3579
3571
  }
3580
- }
3581
- return crossingAssignments;
3582
- }
3583
-
3584
- // lib/ViaGraphSolver/visualizeViaGraphSolver.ts
3585
- var getConnectionColor2 = (connectionId, alpha = 0.8) => {
3586
- let hash = 0;
3587
- for (let i = 0; i < connectionId.length; i++) {
3588
- hash = connectionId.charCodeAt(i) * 17777 + ((hash << 5) - hash);
3589
- }
3590
- const hue = Math.abs(hash) % 360;
3591
- return `hsla(${hue}, 70%, 50%, ${alpha})`;
3592
- };
3593
- var NET_COLOR_PALETTE = [
3594
- "rgba(231, 76, 60, 0.35)",
3595
- // red
3596
- "rgba(46, 204, 113, 0.35)",
3597
- // green
3598
- "rgba(52, 152, 219, 0.35)",
3599
- // blue
3600
- "rgba(243, 156, 18, 0.35)",
3601
- // orange
3602
- "rgba(155, 89, 182, 0.35)",
3603
- // purple
3604
- "rgba(26, 188, 156, 0.35)",
3605
- // teal
3606
- "rgba(241, 196, 15, 0.35)",
3607
- // yellow
3608
- "rgba(230, 126, 34, 0.35)"
3609
- // dark orange
3610
- ];
3611
- var visualizeViaGraphSolver = (solver) => {
3612
- const graph = {
3613
- regions: solver.graph.regions,
3614
- ports: solver.graph.ports
3615
- };
3616
- const graphics = visualizeJumperGraph(graph, {
3617
- connections: solver.connections,
3618
- ...solver.iterations > 0 ? {
3619
- hideRegionPortLines: true,
3620
- hideConnectionLines: true,
3621
- hidePortPoints: true
3622
- } : {}
3623
- });
3624
- const outerIds = /* @__PURE__ */ new Set(["T", "B", "L", "R"]);
3625
- let netColorIndex = 0;
3626
- const netColorMap = /* @__PURE__ */ new Map();
3627
- let polyIndex = 0;
3628
- for (const region of graph.regions) {
3629
- const jRegion = region;
3630
- const hasPolygon = jRegion.d.polygon && jRegion.d.polygon.length >= 3;
3631
- if (!hasPolygon) continue;
3632
- const suffix = jRegion.regionId.split(":").pop() ?? "";
3633
- const isOuter = outerIds.has(suffix);
3634
- if (!isOuter && !jRegion.d.isConnectionRegion) {
3635
- if (!netColorMap.has(suffix)) {
3636
- netColorMap.set(
3637
- suffix,
3638
- NET_COLOR_PALETTE[netColorIndex % NET_COLOR_PALETTE.length]
3639
- );
3640
- netColorIndex++;
3572
+ ],
3573
+ Net8: [
3574
+ {
3575
+ viaId: "26d3bef1-a78f-4947-b551-c48f04289a98",
3576
+ diameter: 0.6,
3577
+ position: {
3578
+ x: 1.553029,
3579
+ y: -0.164505
3641
3580
  }
3642
- if (graphics.polygons[polyIndex]) {
3643
- graphics.polygons[polyIndex].fill = netColorMap.get(suffix);
3581
+ },
3582
+ {
3583
+ viaId: "548acbca-8b68-4186-a589-681ec44fba42",
3584
+ diameter: 0.6,
3585
+ position: {
3586
+ x: 0.222457,
3587
+ y: -1.866711
3588
+ }
3589
+ },
3590
+ {
3591
+ viaId: "d6bf60bf-4b90-4967-a295-fc930b1f2549",
3592
+ diameter: 0.6,
3593
+ position: {
3594
+ x: -1.419706,
3595
+ y: 0.868747
3644
3596
  }
3645
3597
  }
3646
- polyIndex++;
3647
- }
3648
- if (solver.currentConnection && !solver.solved) {
3649
- const connectionColor = getConnectionColor2(
3650
- solver.currentConnection.connectionId
3598
+ ]
3599
+ };
3600
+
3601
+ // lib/ViaGraphSolver/via-graph-generator/generateViaTopologyRegions.ts
3602
+ var TRACE_PITCH = 0.4;
3603
+ var generateViaTopologyRegions = (viasByNet, opts) => {
3604
+ const graphSize = opts?.graphSize ?? 5;
3605
+ const idPrefix = opts?.idPrefix ?? "via";
3606
+ const half = graphSize / 2;
3607
+ const topSegments = [];
3608
+ const bottomSegments = [];
3609
+ const leftSegments = [];
3610
+ const rightSegments = [];
3611
+ for (const vias of Object.values(viasByNet)) {
3612
+ if (vias.length === 0) continue;
3613
+ const topVia = vias.reduce(
3614
+ (best, v) => v.position.y > best.position.y ? v : best
3651
3615
  );
3652
- const startRegion = solver.currentConnection.startRegion;
3653
- const endRegion = solver.currentConnection.endRegion;
3654
- const startCenter = {
3655
- x: (startRegion.d.bounds.minX + startRegion.d.bounds.maxX) / 2,
3656
- y: (startRegion.d.bounds.minY + startRegion.d.bounds.maxY) / 2
3657
- };
3658
- const endCenter = {
3659
- x: (endRegion.d.bounds.minX + endRegion.d.bounds.maxX) / 2,
3660
- y: (endRegion.d.bounds.minY + endRegion.d.bounds.maxY) / 2
3661
- };
3662
- graphics.lines.push({
3663
- points: [startCenter, endCenter],
3664
- strokeColor: connectionColor,
3665
- strokeDash: "10 5"
3616
+ const topY = topVia.position.y + topVia.diameter / 2;
3617
+ topSegments.push({
3618
+ xStart: topVia.position.x - topVia.diameter / 2,
3619
+ xEnd: topVia.position.x + topVia.diameter / 2,
3620
+ y: topY
3666
3621
  });
3667
- graphics.points.push({
3668
- x: startCenter.x - 0.1,
3669
- y: startCenter.y + 0.1,
3670
- color: connectionColor,
3671
- label: [solver.currentConnection.connectionId, "start"].join("\n")
3622
+ const bottomVia = vias.reduce(
3623
+ (best, v) => v.position.y < best.position.y ? v : best
3624
+ );
3625
+ const botY = bottomVia.position.y - bottomVia.diameter / 2;
3626
+ bottomSegments.push({
3627
+ xStart: bottomVia.position.x - bottomVia.diameter / 2,
3628
+ xEnd: bottomVia.position.x + bottomVia.diameter / 2,
3629
+ y: botY
3672
3630
  });
3673
- graphics.points.push({
3674
- x: endCenter.x - 0.1,
3675
- y: endCenter.y + 0.1,
3676
- color: connectionColor,
3677
- label: [solver.currentConnection.connectionId, "end"].join("\n")
3631
+ const leftVia = vias.reduce(
3632
+ (best, v) => v.position.x < best.position.x ? v : best
3633
+ );
3634
+ const leftX = leftVia.position.x - leftVia.diameter / 2;
3635
+ leftSegments.push({
3636
+ x: leftX,
3637
+ yStart: leftVia.position.y - leftVia.diameter / 2,
3638
+ yEnd: leftVia.position.y + leftVia.diameter / 2
3678
3639
  });
3679
- }
3680
- for (const solvedRoute of solver.solvedRoutes) {
3681
- const connectionColor = getConnectionColor2(
3682
- solvedRoute.connection.connectionId
3640
+ const rightVia = vias.reduce(
3641
+ (best, v) => v.position.x > best.position.x ? v : best
3683
3642
  );
3684
- const pathPoints = [];
3685
- for (const candidate of solvedRoute.path) {
3686
- const port = candidate.port;
3687
- pathPoints.push({ x: port.d.x, y: port.d.y });
3688
- }
3689
- if (pathPoints.length > 0) {
3690
- graphics.lines.push({
3691
- points: pathPoints,
3692
- strokeColor: connectionColor
3693
- });
3694
- }
3695
- }
3696
- const candidates = solver.candidateQueue.peekMany(10);
3697
- for (let candidateIndex = 0; candidateIndex < candidates.length; candidateIndex++) {
3698
- const candidate = candidates[candidateIndex];
3699
- const port = candidate.port;
3700
- const isNext = candidateIndex === 0;
3701
- graphics.points.push({
3702
- x: port.d.x,
3703
- y: port.d.y,
3704
- color: isNext ? "green" : "rgba(128, 128, 128, 0.25)",
3705
- label: [
3706
- candidate.port.portId,
3707
- `g: ${candidate.g.toFixed(2)}`,
3708
- `h: ${candidate.h.toFixed(2)}`,
3709
- `f: ${candidate.f.toFixed(2)}`
3710
- ].join("\n")
3643
+ const rightX = rightVia.position.x + rightVia.diameter / 2;
3644
+ rightSegments.push({
3645
+ x: rightX,
3646
+ yStart: rightVia.position.y - rightVia.diameter / 2,
3647
+ yEnd: rightVia.position.y + rightVia.diameter / 2
3711
3648
  });
3712
3649
  }
3713
- const nextCandidate = candidates[0];
3714
- if (!solver.solved && nextCandidate && solver.currentConnection) {
3715
- const connectionColor = getConnectionColor2(
3716
- solver.currentConnection.connectionId
3717
- );
3718
- const activePath = [];
3719
- let cursor = nextCandidate;
3720
- while (cursor) {
3721
- const port = cursor.port;
3722
- activePath.unshift({ x: port.d.x, y: port.d.y });
3723
- cursor = cursor.parent;
3724
- }
3725
- if (activePath.length > 1) {
3726
- graphics.lines.push({
3727
- points: activePath,
3728
- strokeColor: connectionColor
3729
- });
3650
+ topSegments.sort((a, b) => a.xStart - b.xStart);
3651
+ bottomSegments.sort((a, b) => a.xStart - b.xStart);
3652
+ leftSegments.sort((a, b) => a.yStart - b.yStart);
3653
+ rightSegments.sort((a, b) => a.yStart - b.yStart);
3654
+ const lTop = leftSegments[leftSegments.length - 1];
3655
+ const lBot = leftSegments[0];
3656
+ const rTop = rightSegments[rightSegments.length - 1];
3657
+ const rBot = rightSegments[0];
3658
+ const boundsFromPolygon = (points) => {
3659
+ let minX = Infinity;
3660
+ let maxX = -Infinity;
3661
+ let minY = Infinity;
3662
+ let maxY = -Infinity;
3663
+ for (const p of points) {
3664
+ if (p.x < minX) minX = p.x;
3665
+ if (p.x > maxX) maxX = p.x;
3666
+ if (p.y < minY) minY = p.y;
3667
+ if (p.y > maxY) maxY = p.y;
3730
3668
  }
3731
- }
3732
- if (solver.viasByNet) {
3733
- if (!graphics.circles) graphics.circles = [];
3734
- for (const [netName, vias] of Object.entries(solver.viasByNet)) {
3735
- const netColor = netColorMap.get(netName);
3736
- const viaFill = netColor ? netColor.replace("0.35", "0.5") : "rgba(255, 0, 0, 0.3)";
3737
- for (const via of vias) {
3738
- graphics.circles.push({
3739
- center: via.position,
3740
- radius: via.diameter / 2,
3741
- fill: viaFill,
3742
- label: netName
3743
- });
3669
+ return { minX, maxX, minY, maxY };
3670
+ };
3671
+ const createRegion = (id, polygon, opts2) => {
3672
+ const bounds = boundsFromPolygon(polygon);
3673
+ return {
3674
+ regionId: `${idPrefix}:${id}`,
3675
+ ports: [],
3676
+ d: {
3677
+ bounds,
3678
+ center: {
3679
+ x: (bounds.minX + bounds.maxX) / 2,
3680
+ y: (bounds.minY + bounds.maxY) / 2
3681
+ },
3682
+ polygon,
3683
+ isPad: false,
3684
+ isViaRegion: opts2?.isViaRegion
3744
3685
  }
3745
- }
3746
- }
3747
- return graphics;
3748
- };
3749
-
3750
- // lib/ViaGraphSolver/ViaGraphSolver.ts
3751
- var VIA_GRAPH_SOLVER_DEFAULTS = {
3752
- portUsagePenalty: 0.034685181009478865,
3753
- portUsagePenaltySq: 0,
3754
- crossingPenalty: 4.072520483177124,
3755
- crossingPenaltySq: 0,
3756
- ripCost: 35.38577539020022,
3757
- greedyMultiplier: 0.5518001238069296
3758
- };
3759
- var ViaGraphSolver = class extends HyperGraphSolver {
3760
- getSolverName() {
3761
- return "ViaGraphSolver";
3686
+ };
3687
+ };
3688
+ const topPolygon = [];
3689
+ topPolygon.push({ x: -half, y: half });
3690
+ topPolygon.push({ x: half, y: half });
3691
+ topPolygon.push({ x: half, y: rTop.yEnd });
3692
+ topPolygon.push({ x: rTop.x, y: rTop.yEnd });
3693
+ const nTop = topSegments.length;
3694
+ for (let i = nTop - 1; i >= 0; i--) {
3695
+ topPolygon.push({ x: topSegments[i].xEnd, y: topSegments[i].y });
3696
+ topPolygon.push({ x: topSegments[i].xStart, y: topSegments[i].y });
3762
3697
  }
3763
- UNIT_OF_COST = "hops";
3764
- viasByNet;
3765
- portUsagePenalty = VIA_GRAPH_SOLVER_DEFAULTS.portUsagePenalty;
3766
- portUsagePenaltySq = VIA_GRAPH_SOLVER_DEFAULTS.portUsagePenaltySq;
3767
- crossingPenalty = VIA_GRAPH_SOLVER_DEFAULTS.crossingPenalty;
3768
- crossingPenaltySq = VIA_GRAPH_SOLVER_DEFAULTS.crossingPenaltySq;
3769
- ripCost = VIA_GRAPH_SOLVER_DEFAULTS.ripCost;
3770
- baseMaxIterations = 9e5;
3771
- additionalMaxIterationsPerConnection = 2e3;
3772
- additionalMaxIterationsPerCrossing = 2e3;
3773
- constructor(input) {
3774
- super({
3775
- greedyMultiplier: VIA_GRAPH_SOLVER_DEFAULTS.greedyMultiplier,
3776
- rippingEnabled: true,
3777
- ...input
3698
+ topPolygon.push({ x: lTop.x, y: lTop.yEnd });
3699
+ topPolygon.push({ x: -half, y: lTop.yEnd });
3700
+ const topRegion = createRegion("T", topPolygon);
3701
+ const bottomPolygon = [];
3702
+ bottomPolygon.push({ x: -half, y: -half });
3703
+ bottomPolygon.push({ x: half, y: -half });
3704
+ bottomPolygon.push({ x: half, y: rBot.yStart });
3705
+ bottomPolygon.push({ x: rBot.x, y: rBot.yStart });
3706
+ const nBot = bottomSegments.length;
3707
+ for (let i = nBot - 1; i >= 0; i--) {
3708
+ bottomPolygon.push({ x: bottomSegments[i].xEnd, y: bottomSegments[i].y });
3709
+ bottomPolygon.push({
3710
+ x: bottomSegments[i].xStart,
3711
+ y: bottomSegments[i].y
3778
3712
  });
3779
- this.viasByNet = input.viasByNet;
3780
- this.ripCost = input.ripCost ?? this.ripCost;
3781
- this.portUsagePenalty = input.portUsagePenalty ?? this.portUsagePenalty;
3782
- this.crossingPenalty = input.crossingPenalty ?? this.crossingPenalty;
3783
- this.baseMaxIterations = input.baseMaxIterations ?? this.baseMaxIterations;
3784
- this.additionalMaxIterationsPerConnection = input.additionalMaxIterationsPerConnection ?? this.additionalMaxIterationsPerConnection;
3785
- const crossings = countInputConnectionCrossings(
3786
- this.graph,
3787
- input.inputConnections
3788
- );
3789
- this.MAX_ITERATIONS = this.baseMaxIterations + input.inputConnections.length * this.additionalMaxIterationsPerConnection + crossings * this.additionalMaxIterationsPerCrossing;
3790
- this.populateDistanceToEndMaps();
3791
- }
3792
- populateDistanceToEndMaps() {
3793
- const endRegions = new Set(this.connections.map((c) => c.endRegion));
3794
- for (const endRegion of endRegions) {
3795
- const regionDistanceMap = /* @__PURE__ */ new Map();
3796
- const queue = [];
3797
- regionDistanceMap.set(endRegion.regionId, 0);
3798
- queue.push({ region: endRegion, distance: 0 });
3799
- while (queue.length > 0) {
3800
- const { region, distance: dist } = queue.shift();
3801
- for (const port of region.ports) {
3802
- const otherRegion = port.region1 === region ? port.region2 : port.region1;
3803
- if (!regionDistanceMap.has(otherRegion.regionId)) {
3804
- regionDistanceMap.set(otherRegion.regionId, dist + 1);
3805
- queue.push({ region: otherRegion, distance: dist + 1 });
3806
- }
3807
- }
3808
- }
3809
- for (const port of this.graph.ports) {
3810
- if (!port.distanceToEndMap) {
3811
- port.distanceToEndMap = {};
3812
- }
3813
- const d1 = regionDistanceMap.get(port.region1.regionId) ?? Infinity;
3814
- const d2 = regionDistanceMap.get(port.region2.regionId) ?? Infinity;
3815
- port.distanceToEndMap[endRegion.regionId] = Math.min(d1, d2);
3816
- }
3817
- }
3818
- }
3819
- estimateCostToEnd(port) {
3820
- const endRegionId = this.currentEndRegion.regionId;
3821
- const hopDistance = port.distanceToEndMap[endRegionId];
3822
- return hopDistance;
3823
3713
  }
3824
- getPortUsagePenalty(port) {
3825
- const ripCount = port.ripCount ?? 0;
3826
- return ripCount * this.portUsagePenalty + ripCount * this.portUsagePenaltySq;
3714
+ bottomPolygon.push({ x: lBot.x, y: lBot.yStart });
3715
+ bottomPolygon.push({ x: -half, y: lBot.yStart });
3716
+ const bottomRegion = createRegion("B", bottomPolygon);
3717
+ const rightPolygon = [];
3718
+ rightPolygon.push({ x: half, y: rBot.yStart });
3719
+ rightPolygon.push({ x: rBot.x, y: rBot.yStart });
3720
+ for (let i = 0; i < rightSegments.length; i++) {
3721
+ rightPolygon.push({ x: rightSegments[i].x, y: rightSegments[i].yStart });
3722
+ rightPolygon.push({ x: rightSegments[i].x, y: rightSegments[i].yEnd });
3827
3723
  }
3828
- computeIncreasedRegionCostIfPortsAreUsed(region, port1, port2) {
3829
- if (region.d.isViaRegion) {
3830
- const assignments = region.assignments ?? [];
3831
- const differentNetCount = assignments.filter(
3832
- (a) => a.connection.mutuallyConnectedNetworkId !== this.currentConnection.mutuallyConnectedNetworkId
3833
- ).length;
3834
- if (differentNetCount > 0) {
3835
- return differentNetCount * this.crossingPenalty + differentNetCount * this.crossingPenaltySq;
3836
- }
3837
- return 0;
3838
- }
3839
- const crossings = computeDifferentNetCrossingsForPolygon(
3840
- region,
3841
- port1,
3842
- port2
3843
- );
3844
- return crossings * this.crossingPenalty + crossings * this.crossingPenaltySq;
3724
+ rightPolygon.push({ x: half, y: rTop.yEnd });
3725
+ const rightRegion = createRegion("R", rightPolygon);
3726
+ const leftPolygon = [];
3727
+ leftPolygon.push({ x: -half, y: lBot.yStart });
3728
+ leftPolygon.push({ x: lBot.x, y: lBot.yStart });
3729
+ for (let i = 0; i < leftSegments.length; i++) {
3730
+ leftPolygon.push({ x: leftSegments[i].x, y: leftSegments[i].yStart });
3731
+ leftPolygon.push({ x: leftSegments[i].x, y: leftSegments[i].yEnd });
3845
3732
  }
3846
- getRipsRequiredForPortUsage(region, port1, port2) {
3847
- if (region.d.isViaRegion) {
3848
- const assignments = region.assignments ?? [];
3849
- return assignments.filter(
3850
- (a) => a.connection.mutuallyConnectedNetworkId !== this.currentConnection.mutuallyConnectedNetworkId
3851
- );
3733
+ leftPolygon.push({ x: -half, y: lTop.yEnd });
3734
+ const leftRegion = createRegion("L", leftPolygon);
3735
+ const regions = [topRegion, bottomRegion, leftRegion, rightRegion];
3736
+ const ports = [];
3737
+ const createPort = (id, region1, region2, x, y) => {
3738
+ const port = {
3739
+ portId: `${idPrefix}:${id}`,
3740
+ region1,
3741
+ region2,
3742
+ d: { x, y }
3743
+ };
3744
+ region1.ports.push(port);
3745
+ region2.ports.push(port);
3746
+ return port;
3747
+ };
3748
+ const createHorizontalPorts = (groupId, region1, region2, xStart, xEnd, y) => {
3749
+ const length = Math.abs(xEnd - xStart);
3750
+ const count = Math.max(1, Math.floor(length / TRACE_PITCH));
3751
+ const minX = Math.min(xStart, xEnd);
3752
+ for (let i = 0; i < count; i++) {
3753
+ const t = (i + 0.5) / count;
3754
+ const x = minX + t * length;
3755
+ const portId = count === 1 ? groupId : `${groupId}_${i}`;
3756
+ ports.push(createPort(portId, region1, region2, x, y));
3852
3757
  }
3853
- const crossingAssignments = computeCrossingAssignmentsForPolygon(
3854
- region,
3855
- port1,
3856
- port2
3857
- );
3858
- return crossingAssignments.filter(
3859
- (a) => a.connection.mutuallyConnectedNetworkId !== this.currentConnection.mutuallyConnectedNetworkId
3860
- );
3861
- }
3862
- routeSolvedHook(solvedRoute) {
3863
- }
3864
- routeStartedHook(connection) {
3865
- }
3866
- visualize() {
3867
- return visualizeViaGraphSolver(this);
3868
- }
3869
- };
3870
-
3871
- // lib/ViaGraphSolver/via-graph-generator/findBoundaryRegionForPolygons.ts
3872
- function closestPointOnPolygonEdge(point, polygon) {
3873
- let bestDist = Infinity;
3874
- let bestPoint = { x: point.x, y: point.y };
3875
- for (let i = 0; i < polygon.length; i++) {
3876
- const a = polygon[i];
3877
- const b = polygon[(i + 1) % polygon.length];
3878
- const dx = b.x - a.x;
3879
- const dy = b.y - a.y;
3880
- const lenSq = dx * dx + dy * dy;
3881
- if (lenSq < 1e-10) continue;
3882
- const t = Math.max(
3883
- 0,
3884
- Math.min(1, ((point.x - a.x) * dx + (point.y - a.y) * dy) / lenSq)
3885
- );
3886
- const projX = a.x + t * dx;
3887
- const projY = a.y + t * dy;
3888
- const dist = Math.sqrt((point.x - projX) ** 2 + (point.y - projY) ** 2);
3889
- if (dist < bestDist) {
3890
- bestDist = dist;
3891
- bestPoint = { x: projX, y: projY };
3892
- }
3893
- }
3894
- return { ...bestPoint, dist: bestDist };
3895
- }
3896
- var findBoundaryRegionForPolygons = (x, y, regions) => {
3897
- let closestRegion = null;
3898
- let closestDistance = Infinity;
3899
- let closestPortPosition = { x, y };
3900
- for (const region of regions) {
3901
- if (region.d.isPad || region.d.isThroughJumper || region.d.isConnectionRegion)
3902
- continue;
3903
- const polygon = region.d.polygon;
3904
- if (!polygon || polygon.length < 3) continue;
3905
- const result = closestPointOnPolygonEdge({ x, y }, polygon);
3906
- if (result.dist < closestDistance) {
3907
- closestDistance = result.dist;
3908
- closestRegion = region;
3909
- closestPortPosition = { x: result.x, y: result.y };
3910
- }
3911
- }
3912
- if (closestRegion) {
3913
- return { region: closestRegion, portPosition: closestPortPosition };
3914
- }
3915
- return null;
3916
- };
3917
-
3918
- // lib/ViaGraphSolver/via-graph-generator/createViaGraphWithConnections.ts
3919
- var createViaGraphWithConnections = (baseGraph, xyConnections) => {
3920
- const regions = [...baseGraph.regions];
3921
- const ports = [...baseGraph.ports];
3922
- const connections = [];
3923
- for (const xyConn of xyConnections) {
3924
- const { start, end, connectionId } = xyConn;
3925
- const startRegion = createConnectionRegion(
3926
- `conn:${connectionId}:start`,
3927
- start.x,
3928
- start.y
3929
- );
3930
- regions.push(startRegion);
3931
- const endRegion = createConnectionRegion(
3932
- `conn:${connectionId}:end`,
3933
- end.x,
3934
- end.y
3935
- );
3936
- regions.push(endRegion);
3937
- const startBoundary = findBoundaryRegionForPolygons(
3938
- start.x,
3939
- start.y,
3940
- baseGraph.regions
3941
- );
3942
- if (startBoundary) {
3943
- const startPort = createConnectionPort(
3944
- `conn:${connectionId}:start-port`,
3945
- startRegion,
3946
- startBoundary.region,
3947
- startBoundary.portPosition
3948
- );
3949
- ports.push(startPort);
3950
- }
3951
- const endBoundary = findBoundaryRegionForPolygons(
3952
- end.x,
3953
- end.y,
3954
- baseGraph.regions
3955
- );
3956
- if (endBoundary) {
3957
- const endPort = createConnectionPort(
3958
- `conn:${connectionId}:end-port`,
3959
- endRegion,
3960
- endBoundary.region,
3961
- endBoundary.portPosition
3962
- );
3963
- ports.push(endPort);
3964
- }
3965
- const connection = {
3966
- connectionId,
3967
- mutuallyConnectedNetworkId: connectionId,
3968
- startRegion,
3969
- endRegion
3970
- };
3971
- connections.push(connection);
3972
- }
3973
- return {
3974
- regions,
3975
- ports,
3976
- connections
3977
3758
  };
3978
- };
3979
-
3980
- // lib/ViaGraphSolver/via-graph-generator/generateViaTopologyRegions.ts
3981
- var TRACE_PITCH = 0.4;
3982
- var generateViaTopologyRegions = (viasByNet, opts) => {
3983
- const graphSize = opts?.graphSize ?? 5;
3984
- const idPrefix = opts?.idPrefix ?? "via";
3985
- const half = graphSize / 2;
3986
- const topSegments = [];
3987
- const bottomSegments = [];
3988
- const leftSegments = [];
3989
- const rightSegments = [];
3990
- for (const vias of Object.values(viasByNet)) {
3759
+ createHorizontalPorts("T-R", topRegion, rightRegion, rTop.x, half, rTop.yEnd);
3760
+ createHorizontalPorts("T-L", topRegion, leftRegion, -half, lTop.x, lTop.yEnd);
3761
+ createHorizontalPorts(
3762
+ "B-R",
3763
+ bottomRegion,
3764
+ rightRegion,
3765
+ rBot.x,
3766
+ half,
3767
+ rBot.yStart
3768
+ );
3769
+ createHorizontalPorts(
3770
+ "B-L",
3771
+ bottomRegion,
3772
+ leftRegion,
3773
+ -half,
3774
+ lBot.x,
3775
+ lBot.yStart
3776
+ );
3777
+ for (const [netName, vias] of Object.entries(viasByNet)) {
3991
3778
  if (vias.length === 0) continue;
3992
3779
  const topVia = vias.reduce(
3993
3780
  (best, v) => v.position.y > best.position.y ? v : best
3994
3781
  );
3995
- const topY = topVia.position.y + topVia.diameter / 2;
3996
- topSegments.push({
3997
- xStart: topVia.position.x - topVia.diameter / 2,
3998
- xEnd: topVia.position.x + topVia.diameter / 2,
3999
- y: topY
4000
- });
4001
3782
  const bottomVia = vias.reduce(
4002
3783
  (best, v) => v.position.y < best.position.y ? v : best
4003
3784
  );
4004
- const botY = bottomVia.position.y - bottomVia.diameter / 2;
4005
- bottomSegments.push({
4006
- xStart: bottomVia.position.x - bottomVia.diameter / 2,
4007
- xEnd: bottomVia.position.x + bottomVia.diameter / 2,
4008
- y: botY
4009
- });
4010
3785
  const leftVia = vias.reduce(
4011
3786
  (best, v) => v.position.x < best.position.x ? v : best
4012
3787
  );
4013
- const leftX = leftVia.position.x - leftVia.diameter / 2;
4014
- leftSegments.push({
4015
- x: leftX,
4016
- yStart: leftVia.position.y - leftVia.diameter / 2,
4017
- yEnd: leftVia.position.y + leftVia.diameter / 2
4018
- });
4019
3788
  const rightVia = vias.reduce(
4020
3789
  (best, v) => v.position.x > best.position.x ? v : best
4021
3790
  );
4022
- const rightX = rightVia.position.x + rightVia.diameter / 2;
4023
- rightSegments.push({
4024
- x: rightX,
4025
- yStart: rightVia.position.y - rightVia.diameter / 2,
4026
- yEnd: rightVia.position.y + rightVia.diameter / 2
4027
- });
4028
- }
4029
- topSegments.sort((a, b) => a.xStart - b.xStart);
4030
- bottomSegments.sort((a, b) => a.xStart - b.xStart);
4031
- leftSegments.sort((a, b) => a.yStart - b.yStart);
4032
- rightSegments.sort((a, b) => a.yStart - b.yStart);
4033
- const lTop = leftSegments[leftSegments.length - 1];
4034
- const lBot = leftSegments[0];
4035
- const rTop = rightSegments[rightSegments.length - 1];
4036
- const rBot = rightSegments[0];
4037
- const boundsFromPolygon = (points) => {
4038
- let minX = Infinity;
4039
- let maxX = -Infinity;
4040
- let minY = Infinity;
4041
- let maxY = -Infinity;
4042
- for (const p of points) {
4043
- if (p.x < minX) minX = p.x;
4044
- if (p.x > maxX) maxX = p.x;
4045
- if (p.y < minY) minY = p.y;
4046
- if (p.y > maxY) maxY = p.y;
4047
- }
4048
- return { minX, maxX, minY, maxY };
4049
- };
4050
- const createRegion = (id, polygon, opts2) => {
4051
- const bounds = boundsFromPolygon(polygon);
4052
- return {
4053
- regionId: `${idPrefix}:${id}`,
4054
- ports: [],
4055
- d: {
4056
- bounds,
4057
- center: {
4058
- x: (bounds.minX + bounds.maxX) / 2,
4059
- y: (bounds.minY + bounds.maxY) / 2
4060
- },
4061
- polygon,
4062
- isPad: false,
4063
- isViaRegion: opts2?.isViaRegion
4064
- }
4065
- };
4066
- };
4067
- const topPolygon = [];
4068
- topPolygon.push({ x: -half, y: half });
4069
- topPolygon.push({ x: half, y: half });
4070
- topPolygon.push({ x: half, y: rTop.yEnd });
4071
- topPolygon.push({ x: rTop.x, y: rTop.yEnd });
4072
- const nTop = topSegments.length;
4073
- for (let i = nTop - 1; i >= 0; i--) {
4074
- topPolygon.push({ x: topSegments[i].xEnd, y: topSegments[i].y });
4075
- topPolygon.push({ x: topSegments[i].xStart, y: topSegments[i].y });
4076
- }
4077
- topPolygon.push({ x: lTop.x, y: lTop.yEnd });
4078
- topPolygon.push({ x: -half, y: lTop.yEnd });
4079
- const topRegion = createRegion("T", topPolygon);
4080
- const bottomPolygon = [];
4081
- bottomPolygon.push({ x: -half, y: -half });
4082
- bottomPolygon.push({ x: half, y: -half });
4083
- bottomPolygon.push({ x: half, y: rBot.yStart });
4084
- bottomPolygon.push({ x: rBot.x, y: rBot.yStart });
4085
- const nBot = bottomSegments.length;
4086
- for (let i = nBot - 1; i >= 0; i--) {
4087
- bottomPolygon.push({ x: bottomSegments[i].xEnd, y: bottomSegments[i].y });
4088
- bottomPolygon.push({
4089
- x: bottomSegments[i].xStart,
4090
- y: bottomSegments[i].y
4091
- });
4092
- }
4093
- bottomPolygon.push({ x: lBot.x, y: lBot.yStart });
4094
- bottomPolygon.push({ x: -half, y: lBot.yStart });
4095
- const bottomRegion = createRegion("B", bottomPolygon);
4096
- const rightPolygon = [];
4097
- rightPolygon.push({ x: half, y: rBot.yStart });
4098
- rightPolygon.push({ x: rBot.x, y: rBot.yStart });
4099
- for (let i = 0; i < rightSegments.length; i++) {
4100
- rightPolygon.push({ x: rightSegments[i].x, y: rightSegments[i].yStart });
4101
- rightPolygon.push({ x: rightSegments[i].x, y: rightSegments[i].yEnd });
4102
- }
4103
- rightPolygon.push({ x: half, y: rTop.yEnd });
4104
- const rightRegion = createRegion("R", rightPolygon);
4105
- const leftPolygon = [];
4106
- leftPolygon.push({ x: -half, y: lBot.yStart });
4107
- leftPolygon.push({ x: lBot.x, y: lBot.yStart });
4108
- for (let i = 0; i < leftSegments.length; i++) {
4109
- leftPolygon.push({ x: leftSegments[i].x, y: leftSegments[i].yStart });
4110
- leftPolygon.push({ x: leftSegments[i].x, y: leftSegments[i].yEnd });
4111
- }
4112
- leftPolygon.push({ x: -half, y: lTop.yEnd });
4113
- const leftRegion = createRegion("L", leftPolygon);
4114
- const regions = [topRegion, bottomRegion, leftRegion, rightRegion];
4115
- const ports = [];
4116
- const createPort = (id, region1, region2, x, y) => {
4117
- const port = {
4118
- portId: `${idPrefix}:${id}`,
4119
- region1,
4120
- region2,
4121
- d: { x, y }
4122
- };
4123
- region1.ports.push(port);
4124
- region2.ports.push(port);
4125
- return port;
4126
- };
4127
- const createHorizontalPorts = (groupId, region1, region2, xStart, xEnd, y) => {
4128
- const length = Math.abs(xEnd - xStart);
4129
- const count = Math.max(1, Math.floor(length / TRACE_PITCH));
4130
- const minX = Math.min(xStart, xEnd);
4131
- for (let i = 0; i < count; i++) {
4132
- const t = (i + 0.5) / count;
4133
- const x = minX + t * length;
4134
- const portId = count === 1 ? groupId : `${groupId}_${i}`;
4135
- ports.push(createPort(portId, region1, region2, x, y));
4136
- }
4137
- };
4138
- createHorizontalPorts("T-R", topRegion, rightRegion, rTop.x, half, rTop.yEnd);
4139
- createHorizontalPorts("T-L", topRegion, leftRegion, -half, lTop.x, lTop.yEnd);
4140
- createHorizontalPorts(
4141
- "B-R",
4142
- bottomRegion,
4143
- rightRegion,
4144
- rBot.x,
4145
- half,
4146
- rBot.yStart
4147
- );
4148
- createHorizontalPorts(
4149
- "B-L",
4150
- bottomRegion,
4151
- leftRegion,
4152
- -half,
4153
- lBot.x,
4154
- lBot.yStart
4155
- );
4156
- for (const [netName, vias] of Object.entries(viasByNet)) {
4157
- if (vias.length === 0) continue;
4158
- const topVia = vias.reduce(
4159
- (best, v) => v.position.y > best.position.y ? v : best
4160
- );
4161
- const bottomVia = vias.reduce(
4162
- (best, v) => v.position.y < best.position.y ? v : best
4163
- );
4164
- const leftVia = vias.reduce(
4165
- (best, v) => v.position.x < best.position.x ? v : best
4166
- );
4167
- const rightVia = vias.reduce(
4168
- (best, v) => v.position.x > best.position.x ? v : best
4169
- );
4170
- const netTopSeg = {
4171
- xStart: topVia.position.x - topVia.diameter / 2,
4172
- xEnd: topVia.position.x + topVia.diameter / 2,
4173
- y: topVia.position.y + topVia.diameter / 2
4174
- };
4175
- const netBotSeg = {
4176
- xStart: bottomVia.position.x - bottomVia.diameter / 2,
4177
- xEnd: bottomVia.position.x + bottomVia.diameter / 2,
4178
- y: bottomVia.position.y - bottomVia.diameter / 2
4179
- };
4180
- const netLeftSeg = {
4181
- x: leftVia.position.x - leftVia.diameter / 2,
4182
- yStart: leftVia.position.y - leftVia.diameter / 2,
4183
- yEnd: leftVia.position.y + leftVia.diameter / 2
4184
- };
4185
- const netRightSeg = {
4186
- x: rightVia.position.x + rightVia.diameter / 2,
3791
+ const netTopSeg = {
3792
+ xStart: topVia.position.x - topVia.diameter / 2,
3793
+ xEnd: topVia.position.x + topVia.diameter / 2,
3794
+ y: topVia.position.y + topVia.diameter / 2
3795
+ };
3796
+ const netBotSeg = {
3797
+ xStart: bottomVia.position.x - bottomVia.diameter / 2,
3798
+ xEnd: bottomVia.position.x + bottomVia.diameter / 2,
3799
+ y: bottomVia.position.y - bottomVia.diameter / 2
3800
+ };
3801
+ const netLeftSeg = {
3802
+ x: leftVia.position.x - leftVia.diameter / 2,
3803
+ yStart: leftVia.position.y - leftVia.diameter / 2,
3804
+ yEnd: leftVia.position.y + leftVia.diameter / 2
3805
+ };
3806
+ const netRightSeg = {
3807
+ x: rightVia.position.x + rightVia.diameter / 2,
4187
3808
  yStart: rightVia.position.y - rightVia.diameter / 2,
4188
3809
  yEnd: rightVia.position.y + rightVia.diameter / 2
4189
3810
  };
@@ -4742,108 +4363,606 @@ function generateViaTopologyGrid(opts) {
4742
4363
  );
4743
4364
  }
4744
4365
  }
4745
- }
4746
- if (outerLeft) {
4747
- const baseGraph = generateViaTopologyRegions(viasByNet, {
4748
- graphSize: tileSize,
4749
- idPrefix: "v"
4750
- });
4751
- const baseT = baseGraph.regions.find((r) => r.regionId === "v:T");
4752
- const baseB = baseGraph.regions.find((r) => r.regionId === "v:B");
4753
- const tLeftSegs = getBoundarySegments(baseT.d.polygon, "left", -half);
4754
- const bLeftSegs = getBoundarySegments(baseB.d.polygon, "left", -half);
4755
- for (let row = 0; row < rows; row++) {
4756
- const tile = tileGraphs[row][0];
4757
- const tileT = findRegionBySuffix(tile, "v:T");
4758
- const tileB = findRegionBySuffix(tile, "v:B");
4759
- const tileCenterY = gridMinY + row * tileSize + half;
4760
- for (const seg of tLeftSegs) {
4761
- allPorts.push(
4762
- ...createBoundaryPorts(
4763
- `outer:L-tileT${row}`,
4764
- outerLeft,
4765
- tileT,
4766
- "vertical",
4767
- gridMinX,
4768
- seg.from + tileCenterY,
4769
- seg.to + tileCenterY,
4770
- portPitch
4771
- )
4772
- );
4773
- }
4774
- for (const seg of bLeftSegs) {
4775
- allPorts.push(
4776
- ...createBoundaryPorts(
4777
- `outer:L-tileB${row}`,
4778
- outerLeft,
4779
- tileB,
4780
- "vertical",
4781
- gridMinX,
4782
- seg.from + tileCenterY,
4783
- seg.to + tileCenterY,
4784
- portPitch
4785
- )
4786
- );
4366
+ }
4367
+ if (outerLeft) {
4368
+ const baseGraph = generateViaTopologyRegions(viasByNet, {
4369
+ graphSize: tileSize,
4370
+ idPrefix: "v"
4371
+ });
4372
+ const baseT = baseGraph.regions.find((r) => r.regionId === "v:T");
4373
+ const baseB = baseGraph.regions.find((r) => r.regionId === "v:B");
4374
+ const tLeftSegs = getBoundarySegments(baseT.d.polygon, "left", -half);
4375
+ const bLeftSegs = getBoundarySegments(baseB.d.polygon, "left", -half);
4376
+ for (let row = 0; row < rows; row++) {
4377
+ const tile = tileGraphs[row][0];
4378
+ const tileT = findRegionBySuffix(tile, "v:T");
4379
+ const tileB = findRegionBySuffix(tile, "v:B");
4380
+ const tileCenterY = gridMinY + row * tileSize + half;
4381
+ for (const seg of tLeftSegs) {
4382
+ allPorts.push(
4383
+ ...createBoundaryPorts(
4384
+ `outer:L-tileT${row}`,
4385
+ outerLeft,
4386
+ tileT,
4387
+ "vertical",
4388
+ gridMinX,
4389
+ seg.from + tileCenterY,
4390
+ seg.to + tileCenterY,
4391
+ portPitch
4392
+ )
4393
+ );
4394
+ }
4395
+ for (const seg of bLeftSegs) {
4396
+ allPorts.push(
4397
+ ...createBoundaryPorts(
4398
+ `outer:L-tileB${row}`,
4399
+ outerLeft,
4400
+ tileB,
4401
+ "vertical",
4402
+ gridMinX,
4403
+ seg.from + tileCenterY,
4404
+ seg.to + tileCenterY,
4405
+ portPitch
4406
+ )
4407
+ );
4408
+ }
4409
+ }
4410
+ }
4411
+ if (outerRight) {
4412
+ const baseGraph = generateViaTopologyRegions(viasByNet, {
4413
+ graphSize: tileSize,
4414
+ idPrefix: "v"
4415
+ });
4416
+ const baseT = baseGraph.regions.find((r) => r.regionId === "v:T");
4417
+ const baseB = baseGraph.regions.find((r) => r.regionId === "v:B");
4418
+ const tRightSegs = getBoundarySegments(baseT.d.polygon, "right", half);
4419
+ const bRightSegs = getBoundarySegments(baseB.d.polygon, "right", half);
4420
+ for (let row = 0; row < rows; row++) {
4421
+ const tile = tileGraphs[row][cols - 1];
4422
+ const tileT = findRegionBySuffix(tile, "v:T");
4423
+ const tileB = findRegionBySuffix(tile, "v:B");
4424
+ const tileCenterY = gridMinY + row * tileSize + half;
4425
+ for (const seg of tRightSegs) {
4426
+ allPorts.push(
4427
+ ...createBoundaryPorts(
4428
+ `outer:R-tileT${row}`,
4429
+ outerRight,
4430
+ tileT,
4431
+ "vertical",
4432
+ gridMaxX,
4433
+ seg.from + tileCenterY,
4434
+ seg.to + tileCenterY,
4435
+ portPitch
4436
+ )
4437
+ );
4438
+ }
4439
+ for (const seg of bRightSegs) {
4440
+ allPorts.push(
4441
+ ...createBoundaryPorts(
4442
+ `outer:R-tileB${row}`,
4443
+ outerRight,
4444
+ tileB,
4445
+ "vertical",
4446
+ gridMaxX,
4447
+ seg.from + tileCenterY,
4448
+ seg.to + tileCenterY,
4449
+ portPitch
4450
+ )
4451
+ );
4452
+ }
4453
+ }
4454
+ }
4455
+ } else {
4456
+ if (outerTop && outerBottom) {
4457
+ }
4458
+ if (outerLeft && outerRight) {
4459
+ }
4460
+ }
4461
+ return {
4462
+ regions: allRegions,
4463
+ ports: allPorts,
4464
+ tiledViasByNet,
4465
+ tileCount: { rows, cols }
4466
+ };
4467
+ }
4468
+
4469
+ // lib/ViaGraphSolver/defaultTopology.ts
4470
+ function generateDefaultViaTopologyRegions(opts) {
4471
+ return generateViaTopologyRegions(vias_by_net_default, opts);
4472
+ }
4473
+ function generateDefaultViaTopologyGrid(opts) {
4474
+ return generateViaTopologyGrid({
4475
+ ...opts,
4476
+ viasByNet: vias_by_net_default
4477
+ });
4478
+ }
4479
+
4480
+ // lib/ViaGraphSolver/polygonPerimeterUtils.ts
4481
+ function polygonPerimeterT(p, polygon) {
4482
+ const n = polygon.length;
4483
+ let bestDist = Infinity;
4484
+ let bestEdgeIndex = 0;
4485
+ let bestT = 0;
4486
+ for (let i = 0; i < n; i++) {
4487
+ const a2 = polygon[i];
4488
+ const b2 = polygon[(i + 1) % n];
4489
+ const dx = b2.x - a2.x;
4490
+ const dy = b2.y - a2.y;
4491
+ const lenSq = dx * dx + dy * dy;
4492
+ if (lenSq < 1e-10) continue;
4493
+ const t = Math.max(
4494
+ 0,
4495
+ Math.min(1, ((p.x - a2.x) * dx + (p.y - a2.y) * dy) / lenSq)
4496
+ );
4497
+ const projX = a2.x + t * dx;
4498
+ const projY = a2.y + t * dy;
4499
+ const dist = Math.sqrt((p.x - projX) ** 2 + (p.y - projY) ** 2);
4500
+ if (dist < bestDist) {
4501
+ bestDist = dist;
4502
+ bestEdgeIndex = i;
4503
+ bestT = t;
4504
+ }
4505
+ }
4506
+ let cumulative = 0;
4507
+ for (let i = 0; i < bestEdgeIndex; i++) {
4508
+ const a2 = polygon[i];
4509
+ const b2 = polygon[(i + 1) % n];
4510
+ cumulative += Math.sqrt((b2.x - a2.x) ** 2 + (b2.y - a2.y) ** 2);
4511
+ }
4512
+ const a = polygon[bestEdgeIndex];
4513
+ const b = polygon[(bestEdgeIndex + 1) % n];
4514
+ const edgeLen = Math.sqrt((b.x - a.x) ** 2 + (b.y - a.y) ** 2);
4515
+ cumulative += bestT * edgeLen;
4516
+ return cumulative;
4517
+ }
4518
+ function computeDifferentNetCrossingsForPolygon(region, port1, port2) {
4519
+ const polygon = region.d.polygon;
4520
+ if (!polygon || polygon.length < 3) {
4521
+ return 0;
4522
+ }
4523
+ const t1 = polygonPerimeterT(port1.d, polygon);
4524
+ const t2 = polygonPerimeterT(port2.d, polygon);
4525
+ const newChord = [t1, t2];
4526
+ let crossings = 0;
4527
+ const assignments = region.assignments ?? [];
4528
+ for (const assignment of assignments) {
4529
+ const existingT1 = polygonPerimeterT(
4530
+ assignment.regionPort1.d,
4531
+ polygon
4532
+ );
4533
+ const existingT2 = polygonPerimeterT(
4534
+ assignment.regionPort2.d,
4535
+ polygon
4536
+ );
4537
+ const existingChord = [existingT1, existingT2];
4538
+ if (chordsCross(newChord, existingChord)) {
4539
+ crossings++;
4540
+ }
4541
+ }
4542
+ return crossings;
4543
+ }
4544
+ function computeCrossingAssignmentsForPolygon(region, port1, port2) {
4545
+ const polygon = region.d.polygon;
4546
+ if (!polygon || polygon.length < 3) {
4547
+ return [];
4548
+ }
4549
+ const t1 = polygonPerimeterT(port1.d, polygon);
4550
+ const t2 = polygonPerimeterT(port2.d, polygon);
4551
+ const newChord = [t1, t2];
4552
+ const crossingAssignments = [];
4553
+ const assignments = region.assignments ?? [];
4554
+ for (const assignment of assignments) {
4555
+ const existingT1 = polygonPerimeterT(
4556
+ assignment.regionPort1.d,
4557
+ polygon
4558
+ );
4559
+ const existingT2 = polygonPerimeterT(
4560
+ assignment.regionPort2.d,
4561
+ polygon
4562
+ );
4563
+ const existingChord = [existingT1, existingT2];
4564
+ if (chordsCross(newChord, existingChord)) {
4565
+ crossingAssignments.push(assignment);
4566
+ }
4567
+ }
4568
+ return crossingAssignments;
4569
+ }
4570
+
4571
+ // lib/ViaGraphSolver/visualizeViaGraphSolver.ts
4572
+ var getConnectionColor2 = (connectionId, alpha = 0.8) => {
4573
+ let hash = 0;
4574
+ for (let i = 0; i < connectionId.length; i++) {
4575
+ hash = connectionId.charCodeAt(i) * 17777 + ((hash << 5) - hash);
4576
+ }
4577
+ const hue = Math.abs(hash) % 360;
4578
+ return `hsla(${hue}, 70%, 50%, ${alpha})`;
4579
+ };
4580
+ var NET_COLOR_PALETTE = [
4581
+ "rgba(231, 76, 60, 0.35)",
4582
+ // red
4583
+ "rgba(46, 204, 113, 0.35)",
4584
+ // green
4585
+ "rgba(52, 152, 219, 0.35)",
4586
+ // blue
4587
+ "rgba(243, 156, 18, 0.35)",
4588
+ // orange
4589
+ "rgba(155, 89, 182, 0.35)",
4590
+ // purple
4591
+ "rgba(26, 188, 156, 0.35)",
4592
+ // teal
4593
+ "rgba(241, 196, 15, 0.35)",
4594
+ // yellow
4595
+ "rgba(230, 126, 34, 0.35)"
4596
+ // dark orange
4597
+ ];
4598
+ var visualizeViaGraphSolver = (solver) => {
4599
+ const graph = {
4600
+ regions: solver.graph.regions,
4601
+ ports: solver.graph.ports
4602
+ };
4603
+ const graphics = visualizeJumperGraph(graph, {
4604
+ connections: solver.connections,
4605
+ ...solver.iterations > 0 ? {
4606
+ hideRegionPortLines: true,
4607
+ hideConnectionLines: true,
4608
+ hidePortPoints: true
4609
+ } : {}
4610
+ });
4611
+ const outerIds = /* @__PURE__ */ new Set(["T", "B", "L", "R"]);
4612
+ let netColorIndex = 0;
4613
+ const netColorMap = /* @__PURE__ */ new Map();
4614
+ let polyIndex = 0;
4615
+ for (const region of graph.regions) {
4616
+ const jRegion = region;
4617
+ const hasPolygon = jRegion.d.polygon && jRegion.d.polygon.length >= 3;
4618
+ if (!hasPolygon) continue;
4619
+ const suffix = jRegion.regionId.split(":").pop() ?? "";
4620
+ const isOuter = outerIds.has(suffix);
4621
+ if (!isOuter && !jRegion.d.isConnectionRegion) {
4622
+ if (!netColorMap.has(suffix)) {
4623
+ netColorMap.set(
4624
+ suffix,
4625
+ NET_COLOR_PALETTE[netColorIndex % NET_COLOR_PALETTE.length]
4626
+ );
4627
+ netColorIndex++;
4628
+ }
4629
+ if (graphics.polygons[polyIndex]) {
4630
+ graphics.polygons[polyIndex].fill = netColorMap.get(suffix);
4631
+ }
4632
+ }
4633
+ polyIndex++;
4634
+ }
4635
+ if (solver.currentConnection && !solver.solved) {
4636
+ const connectionColor = getConnectionColor2(
4637
+ solver.currentConnection.connectionId
4638
+ );
4639
+ const startRegion = solver.currentConnection.startRegion;
4640
+ const endRegion = solver.currentConnection.endRegion;
4641
+ const startCenter = {
4642
+ x: (startRegion.d.bounds.minX + startRegion.d.bounds.maxX) / 2,
4643
+ y: (startRegion.d.bounds.minY + startRegion.d.bounds.maxY) / 2
4644
+ };
4645
+ const endCenter = {
4646
+ x: (endRegion.d.bounds.minX + endRegion.d.bounds.maxX) / 2,
4647
+ y: (endRegion.d.bounds.minY + endRegion.d.bounds.maxY) / 2
4648
+ };
4649
+ graphics.lines.push({
4650
+ points: [startCenter, endCenter],
4651
+ strokeColor: connectionColor,
4652
+ strokeDash: "10 5"
4653
+ });
4654
+ graphics.points.push({
4655
+ x: startCenter.x - 0.1,
4656
+ y: startCenter.y + 0.1,
4657
+ color: connectionColor,
4658
+ label: [solver.currentConnection.connectionId, "start"].join("\n")
4659
+ });
4660
+ graphics.points.push({
4661
+ x: endCenter.x - 0.1,
4662
+ y: endCenter.y + 0.1,
4663
+ color: connectionColor,
4664
+ label: [solver.currentConnection.connectionId, "end"].join("\n")
4665
+ });
4666
+ }
4667
+ for (const solvedRoute of solver.solvedRoutes) {
4668
+ const connectionColor = getConnectionColor2(
4669
+ solvedRoute.connection.connectionId
4670
+ );
4671
+ const pathPoints = [];
4672
+ for (const candidate of solvedRoute.path) {
4673
+ const port = candidate.port;
4674
+ pathPoints.push({ x: port.d.x, y: port.d.y });
4675
+ }
4676
+ if (pathPoints.length > 0) {
4677
+ graphics.lines.push({
4678
+ points: pathPoints,
4679
+ strokeColor: connectionColor
4680
+ });
4681
+ }
4682
+ }
4683
+ const candidates = solver.candidateQueue.peekMany(10);
4684
+ for (let candidateIndex = 0; candidateIndex < candidates.length; candidateIndex++) {
4685
+ const candidate = candidates[candidateIndex];
4686
+ const port = candidate.port;
4687
+ const isNext = candidateIndex === 0;
4688
+ graphics.points.push({
4689
+ x: port.d.x,
4690
+ y: port.d.y,
4691
+ color: isNext ? "green" : "rgba(128, 128, 128, 0.25)",
4692
+ label: [
4693
+ candidate.port.portId,
4694
+ `g: ${candidate.g.toFixed(2)}`,
4695
+ `h: ${candidate.h.toFixed(2)}`,
4696
+ `f: ${candidate.f.toFixed(2)}`
4697
+ ].join("\n")
4698
+ });
4699
+ }
4700
+ const nextCandidate = candidates[0];
4701
+ if (!solver.solved && nextCandidate && solver.currentConnection) {
4702
+ const connectionColor = getConnectionColor2(
4703
+ solver.currentConnection.connectionId
4704
+ );
4705
+ const activePath = [];
4706
+ let cursor = nextCandidate;
4707
+ while (cursor) {
4708
+ const port = cursor.port;
4709
+ activePath.unshift({ x: port.d.x, y: port.d.y });
4710
+ cursor = cursor.parent;
4711
+ }
4712
+ if (activePath.length > 1) {
4713
+ graphics.lines.push({
4714
+ points: activePath,
4715
+ strokeColor: connectionColor
4716
+ });
4717
+ }
4718
+ }
4719
+ if (solver.viasByNet) {
4720
+ if (!graphics.circles) graphics.circles = [];
4721
+ for (const [netName, vias] of Object.entries(solver.viasByNet)) {
4722
+ const netColor = netColorMap.get(netName);
4723
+ const viaFill = netColor ? netColor.replace("0.35", "0.5") : "rgba(255, 0, 0, 0.3)";
4724
+ for (const via of vias) {
4725
+ graphics.circles.push({
4726
+ center: via.position,
4727
+ radius: via.diameter / 2,
4728
+ fill: viaFill,
4729
+ label: netName
4730
+ });
4731
+ }
4732
+ }
4733
+ }
4734
+ return graphics;
4735
+ };
4736
+
4737
+ // lib/ViaGraphSolver/ViaGraphSolver.ts
4738
+ var VIA_GRAPH_SOLVER_DEFAULTS = {
4739
+ portUsagePenalty: 0.034685181009478865,
4740
+ portUsagePenaltySq: 0,
4741
+ crossingPenalty: 4.072520483177124,
4742
+ crossingPenaltySq: 0,
4743
+ ripCost: 35.38577539020022,
4744
+ greedyMultiplier: 0.5518001238069296
4745
+ };
4746
+ var ViaGraphSolver = class extends HyperGraphSolver {
4747
+ getSolverName() {
4748
+ return "ViaGraphSolver";
4749
+ }
4750
+ UNIT_OF_COST = "hops";
4751
+ viasByNet;
4752
+ portUsagePenalty = VIA_GRAPH_SOLVER_DEFAULTS.portUsagePenalty;
4753
+ portUsagePenaltySq = VIA_GRAPH_SOLVER_DEFAULTS.portUsagePenaltySq;
4754
+ crossingPenalty = VIA_GRAPH_SOLVER_DEFAULTS.crossingPenalty;
4755
+ crossingPenaltySq = VIA_GRAPH_SOLVER_DEFAULTS.crossingPenaltySq;
4756
+ ripCost = VIA_GRAPH_SOLVER_DEFAULTS.ripCost;
4757
+ baseMaxIterations = 9e5;
4758
+ additionalMaxIterationsPerConnection = 2e3;
4759
+ additionalMaxIterationsPerCrossing = 2e3;
4760
+ constructor(input) {
4761
+ super({
4762
+ greedyMultiplier: VIA_GRAPH_SOLVER_DEFAULTS.greedyMultiplier,
4763
+ rippingEnabled: true,
4764
+ ...input
4765
+ });
4766
+ this.viasByNet = input.viasByNet;
4767
+ this.ripCost = input.ripCost ?? this.ripCost;
4768
+ this.portUsagePenalty = input.portUsagePenalty ?? this.portUsagePenalty;
4769
+ this.crossingPenalty = input.crossingPenalty ?? this.crossingPenalty;
4770
+ this.baseMaxIterations = input.baseMaxIterations ?? this.baseMaxIterations;
4771
+ this.additionalMaxIterationsPerConnection = input.additionalMaxIterationsPerConnection ?? this.additionalMaxIterationsPerConnection;
4772
+ const crossings = countInputConnectionCrossings(
4773
+ this.graph,
4774
+ input.inputConnections
4775
+ );
4776
+ this.MAX_ITERATIONS = this.baseMaxIterations + input.inputConnections.length * this.additionalMaxIterationsPerConnection + crossings * this.additionalMaxIterationsPerCrossing;
4777
+ this.populateDistanceToEndMaps();
4778
+ }
4779
+ populateDistanceToEndMaps() {
4780
+ const endRegions = new Set(this.connections.map((c) => c.endRegion));
4781
+ for (const endRegion of endRegions) {
4782
+ const regionDistanceMap = /* @__PURE__ */ new Map();
4783
+ const queue = [];
4784
+ regionDistanceMap.set(endRegion.regionId, 0);
4785
+ queue.push({ region: endRegion, distance: 0 });
4786
+ while (queue.length > 0) {
4787
+ const { region, distance: dist } = queue.shift();
4788
+ for (const port of region.ports) {
4789
+ const otherRegion = port.region1 === region ? port.region2 : port.region1;
4790
+ if (!regionDistanceMap.has(otherRegion.regionId)) {
4791
+ regionDistanceMap.set(otherRegion.regionId, dist + 1);
4792
+ queue.push({ region: otherRegion, distance: dist + 1 });
4793
+ }
4794
+ }
4795
+ }
4796
+ for (const port of this.graph.ports) {
4797
+ if (!port.distanceToEndMap) {
4798
+ port.distanceToEndMap = {};
4787
4799
  }
4800
+ const d1 = regionDistanceMap.get(port.region1.regionId) ?? Infinity;
4801
+ const d2 = regionDistanceMap.get(port.region2.regionId) ?? Infinity;
4802
+ port.distanceToEndMap[endRegion.regionId] = Math.min(d1, d2);
4788
4803
  }
4789
4804
  }
4790
- if (outerRight) {
4791
- const baseGraph = generateViaTopologyRegions(viasByNet, {
4792
- graphSize: tileSize,
4793
- idPrefix: "v"
4794
- });
4795
- const baseT = baseGraph.regions.find((r) => r.regionId === "v:T");
4796
- const baseB = baseGraph.regions.find((r) => r.regionId === "v:B");
4797
- const tRightSegs = getBoundarySegments(baseT.d.polygon, "right", half);
4798
- const bRightSegs = getBoundarySegments(baseB.d.polygon, "right", half);
4799
- for (let row = 0; row < rows; row++) {
4800
- const tile = tileGraphs[row][cols - 1];
4801
- const tileT = findRegionBySuffix(tile, "v:T");
4802
- const tileB = findRegionBySuffix(tile, "v:B");
4803
- const tileCenterY = gridMinY + row * tileSize + half;
4804
- for (const seg of tRightSegs) {
4805
- allPorts.push(
4806
- ...createBoundaryPorts(
4807
- `outer:R-tileT${row}`,
4808
- outerRight,
4809
- tileT,
4810
- "vertical",
4811
- gridMaxX,
4812
- seg.from + tileCenterY,
4813
- seg.to + tileCenterY,
4814
- portPitch
4815
- )
4816
- );
4817
- }
4818
- for (const seg of bRightSegs) {
4819
- allPorts.push(
4820
- ...createBoundaryPorts(
4821
- `outer:R-tileB${row}`,
4822
- outerRight,
4823
- tileB,
4824
- "vertical",
4825
- gridMaxX,
4826
- seg.from + tileCenterY,
4827
- seg.to + tileCenterY,
4828
- portPitch
4829
- )
4830
- );
4831
- }
4805
+ }
4806
+ estimateCostToEnd(port) {
4807
+ const endRegionId = this.currentEndRegion.regionId;
4808
+ const hopDistance = port.distanceToEndMap[endRegionId];
4809
+ return hopDistance;
4810
+ }
4811
+ getPortUsagePenalty(port) {
4812
+ const ripCount = port.ripCount ?? 0;
4813
+ return ripCount * this.portUsagePenalty + ripCount * this.portUsagePenaltySq;
4814
+ }
4815
+ computeIncreasedRegionCostIfPortsAreUsed(region, port1, port2) {
4816
+ if (region.d.isViaRegion) {
4817
+ const assignments = region.assignments ?? [];
4818
+ const differentNetCount = assignments.filter(
4819
+ (a) => a.connection.mutuallyConnectedNetworkId !== this.currentConnection.mutuallyConnectedNetworkId
4820
+ ).length;
4821
+ if (differentNetCount > 0) {
4822
+ return differentNetCount * this.crossingPenalty + differentNetCount * this.crossingPenaltySq;
4832
4823
  }
4824
+ return 0;
4833
4825
  }
4834
- } else {
4835
- if (outerTop && outerBottom) {
4826
+ const crossings = computeDifferentNetCrossingsForPolygon(
4827
+ region,
4828
+ port1,
4829
+ port2
4830
+ );
4831
+ return crossings * this.crossingPenalty + crossings * this.crossingPenaltySq;
4832
+ }
4833
+ getRipsRequiredForPortUsage(region, port1, port2) {
4834
+ if (region.d.isViaRegion) {
4835
+ const assignments = region.assignments ?? [];
4836
+ return assignments.filter(
4837
+ (a) => a.connection.mutuallyConnectedNetworkId !== this.currentConnection.mutuallyConnectedNetworkId
4838
+ );
4836
4839
  }
4837
- if (outerLeft && outerRight) {
4840
+ const crossingAssignments = computeCrossingAssignmentsForPolygon(
4841
+ region,
4842
+ port1,
4843
+ port2
4844
+ );
4845
+ return crossingAssignments.filter(
4846
+ (a) => a.connection.mutuallyConnectedNetworkId !== this.currentConnection.mutuallyConnectedNetworkId
4847
+ );
4848
+ }
4849
+ routeSolvedHook(solvedRoute) {
4850
+ }
4851
+ routeStartedHook(connection) {
4852
+ }
4853
+ visualize() {
4854
+ return visualizeViaGraphSolver(this);
4855
+ }
4856
+ };
4857
+
4858
+ // lib/ViaGraphSolver/via-graph-generator/findBoundaryRegionForPolygons.ts
4859
+ function closestPointOnPolygonEdge(point, polygon) {
4860
+ let bestDist = Infinity;
4861
+ let bestPoint = { x: point.x, y: point.y };
4862
+ for (let i = 0; i < polygon.length; i++) {
4863
+ const a = polygon[i];
4864
+ const b = polygon[(i + 1) % polygon.length];
4865
+ const dx = b.x - a.x;
4866
+ const dy = b.y - a.y;
4867
+ const lenSq = dx * dx + dy * dy;
4868
+ if (lenSq < 1e-10) continue;
4869
+ const t = Math.max(
4870
+ 0,
4871
+ Math.min(1, ((point.x - a.x) * dx + (point.y - a.y) * dy) / lenSq)
4872
+ );
4873
+ const projX = a.x + t * dx;
4874
+ const projY = a.y + t * dy;
4875
+ const dist = Math.sqrt((point.x - projX) ** 2 + (point.y - projY) ** 2);
4876
+ if (dist < bestDist) {
4877
+ bestDist = dist;
4878
+ bestPoint = { x: projX, y: projY };
4879
+ }
4880
+ }
4881
+ return { ...bestPoint, dist: bestDist };
4882
+ }
4883
+ var findBoundaryRegionForPolygons = (x, y, regions) => {
4884
+ let closestRegion = null;
4885
+ let closestDistance = Infinity;
4886
+ let closestPortPosition = { x, y };
4887
+ for (const region of regions) {
4888
+ if (region.d.isPad || region.d.isThroughJumper || region.d.isConnectionRegion)
4889
+ continue;
4890
+ const polygon = region.d.polygon;
4891
+ if (!polygon || polygon.length < 3) continue;
4892
+ const result = closestPointOnPolygonEdge({ x, y }, polygon);
4893
+ if (result.dist < closestDistance) {
4894
+ closestDistance = result.dist;
4895
+ closestRegion = region;
4896
+ closestPortPosition = { x: result.x, y: result.y };
4897
+ }
4898
+ }
4899
+ if (closestRegion) {
4900
+ return { region: closestRegion, portPosition: closestPortPosition };
4901
+ }
4902
+ return null;
4903
+ };
4904
+
4905
+ // lib/ViaGraphSolver/via-graph-generator/createViaGraphWithConnections.ts
4906
+ var createViaGraphWithConnections = (baseGraph, xyConnections) => {
4907
+ const regions = [...baseGraph.regions];
4908
+ const ports = [...baseGraph.ports];
4909
+ const connections = [];
4910
+ for (const xyConn of xyConnections) {
4911
+ const { start, end, connectionId } = xyConn;
4912
+ const startRegion = createConnectionRegion(
4913
+ `conn:${connectionId}:start`,
4914
+ start.x,
4915
+ start.y
4916
+ );
4917
+ regions.push(startRegion);
4918
+ const endRegion = createConnectionRegion(
4919
+ `conn:${connectionId}:end`,
4920
+ end.x,
4921
+ end.y
4922
+ );
4923
+ regions.push(endRegion);
4924
+ const startBoundary = findBoundaryRegionForPolygons(
4925
+ start.x,
4926
+ start.y,
4927
+ baseGraph.regions
4928
+ );
4929
+ if (startBoundary) {
4930
+ const startPort = createConnectionPort(
4931
+ `conn:${connectionId}:start-port`,
4932
+ startRegion,
4933
+ startBoundary.region,
4934
+ startBoundary.portPosition
4935
+ );
4936
+ ports.push(startPort);
4937
+ }
4938
+ const endBoundary = findBoundaryRegionForPolygons(
4939
+ end.x,
4940
+ end.y,
4941
+ baseGraph.regions
4942
+ );
4943
+ if (endBoundary) {
4944
+ const endPort = createConnectionPort(
4945
+ `conn:${connectionId}:end-port`,
4946
+ endRegion,
4947
+ endBoundary.region,
4948
+ endBoundary.portPosition
4949
+ );
4950
+ ports.push(endPort);
4838
4951
  }
4952
+ const connection = {
4953
+ connectionId,
4954
+ mutuallyConnectedNetworkId: connectionId,
4955
+ startRegion,
4956
+ endRegion
4957
+ };
4958
+ connections.push(connection);
4839
4959
  }
4840
4960
  return {
4841
- regions: allRegions,
4842
- ports: allPorts,
4843
- tiledViasByNet,
4844
- tileCount: { rows, cols }
4961
+ regions,
4962
+ ports,
4963
+ connections
4845
4964
  };
4846
- }
4965
+ };
4847
4966
 
4848
4967
  // lib/ViaGraphSolver/via-graph-generator/createViaGraphFromXYConnections.ts
4849
4968
  function calculateBoundsFromConnections(xyConnections) {
@@ -4901,9 +5020,12 @@ export {
4901
5020
  createGraphWithConnectionsFromBaseGraph,
4902
5021
  createViaGraphFromXYConnections,
4903
5022
  createViaGraphWithConnections,
5023
+ generateDefaultViaTopologyGrid,
5024
+ generateDefaultViaTopologyRegions,
4904
5025
  generateJumperGrid,
4905
5026
  generateJumperX4Grid,
4906
5027
  generateViaTopologyGrid,
4907
5028
  generateViaTopologyRegions,
4908
- rotateGraph90Degrees
5029
+ rotateGraph90Degrees,
5030
+ vias_by_net_default as viasByNet
4909
5031
  };