@tscircuit/hypergraph 0.0.28 → 0.0.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +166 -41
- package/dist/index.js +874 -752
- 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
|
-
//
|
|
3494
|
-
|
|
3495
|
-
|
|
3496
|
-
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
|
|
3505
|
-
|
|
3506
|
-
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
|
|
3513
|
-
|
|
3514
|
-
|
|
3515
|
-
|
|
3516
|
-
|
|
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
|
-
|
|
3520
|
-
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
|
|
3527
|
-
|
|
3528
|
-
|
|
3529
|
-
|
|
3530
|
-
|
|
3531
|
-
|
|
3532
|
-
|
|
3533
|
-
|
|
3534
|
-
|
|
3535
|
-
|
|
3536
|
-
|
|
3537
|
-
|
|
3538
|
-
|
|
3539
|
-
|
|
3540
|
-
|
|
3541
|
-
|
|
3542
|
-
|
|
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
|
-
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
|
|
3561
|
-
|
|
3562
|
-
|
|
3563
|
-
|
|
3564
|
-
|
|
3565
|
-
|
|
3566
|
-
|
|
3567
|
-
|
|
3568
|
-
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
|
|
3574
|
-
|
|
3575
|
-
|
|
3576
|
-
|
|
3577
|
-
|
|
3578
|
-
|
|
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
|
-
|
|
3582
|
-
|
|
3583
|
-
|
|
3584
|
-
|
|
3585
|
-
|
|
3586
|
-
|
|
3587
|
-
|
|
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
|
-
|
|
3643
|
-
|
|
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
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
|
|
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
|
|
3653
|
-
|
|
3654
|
-
|
|
3655
|
-
|
|
3656
|
-
y:
|
|
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
|
-
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
|
|
3671
|
-
|
|
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
|
-
|
|
3674
|
-
x
|
|
3675
|
-
|
|
3676
|
-
|
|
3677
|
-
|
|
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
|
-
|
|
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
|
|
3685
|
-
|
|
3686
|
-
|
|
3687
|
-
|
|
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
|
-
|
|
3714
|
-
|
|
3715
|
-
|
|
3716
|
-
|
|
3717
|
-
|
|
3718
|
-
|
|
3719
|
-
|
|
3720
|
-
|
|
3721
|
-
|
|
3722
|
-
|
|
3723
|
-
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
|
|
3727
|
-
|
|
3728
|
-
|
|
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
|
-
|
|
3733
|
-
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
|
|
3739
|
-
|
|
3740
|
-
|
|
3741
|
-
|
|
3742
|
-
|
|
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
|
-
|
|
3748
|
-
};
|
|
3749
|
-
|
|
3750
|
-
|
|
3751
|
-
|
|
3752
|
-
|
|
3753
|
-
|
|
3754
|
-
|
|
3755
|
-
|
|
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
|
-
|
|
3764
|
-
|
|
3765
|
-
|
|
3766
|
-
|
|
3767
|
-
|
|
3768
|
-
|
|
3769
|
-
|
|
3770
|
-
|
|
3771
|
-
|
|
3772
|
-
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
|
|
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
|
-
|
|
3825
|
-
|
|
3826
|
-
|
|
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
|
-
|
|
3829
|
-
|
|
3830
|
-
|
|
3831
|
-
|
|
3832
|
-
|
|
3833
|
-
|
|
3834
|
-
|
|
3835
|
-
|
|
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
|
-
|
|
3847
|
-
|
|
3848
|
-
|
|
3849
|
-
|
|
3850
|
-
|
|
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
|
-
|
|
3981
|
-
|
|
3982
|
-
|
|
3983
|
-
|
|
3984
|
-
|
|
3985
|
-
|
|
3986
|
-
|
|
3987
|
-
|
|
3988
|
-
|
|
3989
|
-
|
|
3990
|
-
|
|
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
|
|
4023
|
-
|
|
4024
|
-
|
|
4025
|
-
|
|
4026
|
-
|
|
4027
|
-
|
|
4028
|
-
|
|
4029
|
-
|
|
4030
|
-
|
|
4031
|
-
|
|
4032
|
-
|
|
4033
|
-
|
|
4034
|
-
|
|
4035
|
-
|
|
4036
|
-
|
|
4037
|
-
|
|
4038
|
-
|
|
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
|
-
|
|
4791
|
-
|
|
4792
|
-
|
|
4793
|
-
|
|
4794
|
-
|
|
4795
|
-
|
|
4796
|
-
|
|
4797
|
-
|
|
4798
|
-
|
|
4799
|
-
|
|
4800
|
-
|
|
4801
|
-
|
|
4802
|
-
|
|
4803
|
-
|
|
4804
|
-
|
|
4805
|
-
|
|
4806
|
-
|
|
4807
|
-
|
|
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
|
-
|
|
4835
|
-
|
|
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
|
-
|
|
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
|
|
4842
|
-
ports
|
|
4843
|
-
|
|
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
|
};
|