@tscircuit/hypergraph 0.0.43 → 0.0.45
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 +22 -79
- package/dist/index.js +540 -832
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5504,7 +5504,9 @@ var via_tile_4_regions_default = {
|
|
|
5504
5504
|
}
|
|
5505
5505
|
]
|
|
5506
5506
|
}
|
|
5507
|
-
]
|
|
5507
|
+
],
|
|
5508
|
+
tileWidth: 3.735441,
|
|
5509
|
+
tileHeight: 4.029267
|
|
5508
5510
|
};
|
|
5509
5511
|
|
|
5510
5512
|
// lib/ViaGraphSolver/via-graph-generator/generateViaTopologyRegions.ts
|
|
@@ -5770,647 +5772,38 @@ var generateViaTopologyRegions = (viaTile, opts) => {
|
|
|
5770
5772
|
return { regions, ports };
|
|
5771
5773
|
};
|
|
5772
5774
|
|
|
5773
|
-
// lib/ViaGraphSolver/via-graph-generator/generateViaTopologyGrid.ts
|
|
5774
|
-
var DEFAULT_PORT_PITCH = 0.4;
|
|
5775
|
-
var DEFAULT_TILE_SIZE = 5;
|
|
5776
|
-
function translateGraph(graph, dx, dy, prefix) {
|
|
5777
|
-
const regionMap = /* @__PURE__ */ new Map();
|
|
5778
|
-
const regions = graph.regions.map((r) => {
|
|
5779
|
-
const newRegion = {
|
|
5780
|
-
regionId: `${prefix}:${r.regionId}`,
|
|
5781
|
-
ports: [],
|
|
5782
|
-
d: {
|
|
5783
|
-
bounds: {
|
|
5784
|
-
minX: r.d.bounds.minX + dx,
|
|
5785
|
-
maxX: r.d.bounds.maxX + dx,
|
|
5786
|
-
minY: r.d.bounds.minY + dy,
|
|
5787
|
-
maxY: r.d.bounds.maxY + dy
|
|
5788
|
-
},
|
|
5789
|
-
center: {
|
|
5790
|
-
x: r.d.center.x + dx,
|
|
5791
|
-
y: r.d.center.y + dy
|
|
5792
|
-
},
|
|
5793
|
-
polygon: r.d.polygon?.map((p) => ({ x: p.x + dx, y: p.y + dy })),
|
|
5794
|
-
isPad: r.d.isPad,
|
|
5795
|
-
isThroughJumper: r.d.isThroughJumper,
|
|
5796
|
-
isConnectionRegion: r.d.isConnectionRegion,
|
|
5797
|
-
isViaRegion: r.d.isViaRegion
|
|
5798
|
-
}
|
|
5799
|
-
};
|
|
5800
|
-
regionMap.set(r, newRegion);
|
|
5801
|
-
return newRegion;
|
|
5802
|
-
});
|
|
5803
|
-
const ports = graph.ports.map((p) => {
|
|
5804
|
-
const newPort = {
|
|
5805
|
-
portId: `${prefix}:${p.portId}`,
|
|
5806
|
-
region1: regionMap.get(p.region1),
|
|
5807
|
-
region2: regionMap.get(p.region2),
|
|
5808
|
-
d: { x: p.d.x + dx, y: p.d.y + dy }
|
|
5809
|
-
};
|
|
5810
|
-
newPort.region1.ports.push(newPort);
|
|
5811
|
-
newPort.region2.ports.push(newPort);
|
|
5812
|
-
return newPort;
|
|
5813
|
-
});
|
|
5814
|
-
return { regions, ports };
|
|
5815
|
-
}
|
|
5816
|
-
function translateRouteSegments(routeSegments, dx, dy, prefix) {
|
|
5817
|
-
return routeSegments.map((segment2) => ({
|
|
5818
|
-
routeId: `${prefix}:${segment2.routeId}`,
|
|
5819
|
-
fromPort: `${prefix}:${segment2.fromPort}`,
|
|
5820
|
-
toPort: `${prefix}:${segment2.toPort}`,
|
|
5821
|
-
layer: segment2.layer,
|
|
5822
|
-
segments: segment2.segments.map((point2) => ({
|
|
5823
|
-
x: point2.x + dx,
|
|
5824
|
-
y: point2.y + dy
|
|
5825
|
-
}))
|
|
5826
|
-
}));
|
|
5827
|
-
}
|
|
5828
|
-
function createBoundaryPorts(portIdPrefix, region1, region2, axis, fixedCoord, start, end, portPitch) {
|
|
5829
|
-
const length = Math.abs(end - start);
|
|
5830
|
-
if (length < 1e-3) return [];
|
|
5831
|
-
const count = Math.max(1, Math.floor(length / portPitch));
|
|
5832
|
-
const min = Math.min(start, end);
|
|
5833
|
-
const ports = [];
|
|
5834
|
-
for (let i = 0; i < count; i++) {
|
|
5835
|
-
const t = (i + 0.5) / count;
|
|
5836
|
-
const varying = min + t * length;
|
|
5837
|
-
const x = axis === "horizontal" ? varying : fixedCoord;
|
|
5838
|
-
const y = axis === "horizontal" ? fixedCoord : varying;
|
|
5839
|
-
const portId = count === 1 ? portIdPrefix : `${portIdPrefix}_${i}`;
|
|
5840
|
-
const port = {
|
|
5841
|
-
portId,
|
|
5842
|
-
region1,
|
|
5843
|
-
region2,
|
|
5844
|
-
d: { x, y }
|
|
5845
|
-
};
|
|
5846
|
-
region1.ports.push(port);
|
|
5847
|
-
region2.ports.push(port);
|
|
5848
|
-
ports.push(port);
|
|
5849
|
-
}
|
|
5850
|
-
return ports;
|
|
5851
|
-
}
|
|
5852
|
-
function createRectRegion(regionId, minX, maxX, minY, maxY) {
|
|
5853
|
-
const polygon2 = [
|
|
5854
|
-
{ x: minX, y: minY },
|
|
5855
|
-
{ x: maxX, y: minY },
|
|
5856
|
-
{ x: maxX, y: maxY },
|
|
5857
|
-
{ x: minX, y: maxY }
|
|
5858
|
-
];
|
|
5859
|
-
return {
|
|
5860
|
-
regionId,
|
|
5861
|
-
ports: [],
|
|
5862
|
-
d: {
|
|
5863
|
-
bounds: { minX, maxX, minY, maxY },
|
|
5864
|
-
center: { x: (minX + maxX) / 2, y: (minY + maxY) / 2 },
|
|
5865
|
-
polygon: polygon2,
|
|
5866
|
-
isPad: false
|
|
5867
|
-
}
|
|
5868
|
-
};
|
|
5869
|
-
}
|
|
5870
|
-
function findRegionBySuffix(graph, suffix) {
|
|
5871
|
-
const region = graph.regions.find((r) => r.regionId.endsWith(`:${suffix}`));
|
|
5872
|
-
if (!region) throw new Error(`Region with suffix ${suffix} not found`);
|
|
5873
|
-
return region;
|
|
5874
|
-
}
|
|
5875
|
-
function getBoundarySegments(polygon2, edge, boundaryCoord) {
|
|
5876
|
-
const eps = 1e-3;
|
|
5877
|
-
const segments = [];
|
|
5878
|
-
for (let i = 0; i < polygon2.length; i++) {
|
|
5879
|
-
const a = polygon2[i];
|
|
5880
|
-
const b = polygon2[(i + 1) % polygon2.length];
|
|
5881
|
-
const isVerticalEdge = edge === "right" || edge === "left";
|
|
5882
|
-
if (isVerticalEdge) {
|
|
5883
|
-
if (Math.abs(a.x - boundaryCoord) < eps && Math.abs(b.x - boundaryCoord) < eps) {
|
|
5884
|
-
segments.push({ from: Math.min(a.y, b.y), to: Math.max(a.y, b.y) });
|
|
5885
|
-
}
|
|
5886
|
-
} else {
|
|
5887
|
-
if (Math.abs(a.y - boundaryCoord) < eps && Math.abs(b.y - boundaryCoord) < eps) {
|
|
5888
|
-
segments.push({ from: Math.min(a.x, b.x), to: Math.max(a.x, b.x) });
|
|
5889
|
-
}
|
|
5890
|
-
}
|
|
5891
|
-
}
|
|
5892
|
-
return segments;
|
|
5893
|
-
}
|
|
5894
|
-
function rangeOverlap(a, b) {
|
|
5895
|
-
const from = Math.max(a.from, b.from);
|
|
5896
|
-
const to = Math.min(a.to, b.to);
|
|
5897
|
-
if (to - from < 1e-3) return null;
|
|
5898
|
-
return { from, to };
|
|
5899
|
-
}
|
|
5900
|
-
function generateViaTopologyGrid(opts) {
|
|
5901
|
-
const tileSize = opts.tileSize ?? DEFAULT_TILE_SIZE;
|
|
5902
|
-
const portPitch = opts.portPitch ?? DEFAULT_PORT_PITCH;
|
|
5903
|
-
const { bounds, viaTile: inputViaTile } = opts;
|
|
5904
|
-
const { viasByNet, routeSegments } = inputViaTile;
|
|
5905
|
-
const width = bounds.maxX - bounds.minX;
|
|
5906
|
-
const height = bounds.maxY - bounds.minY;
|
|
5907
|
-
const cols = Math.floor(width / tileSize);
|
|
5908
|
-
const rows = Math.floor(height / tileSize);
|
|
5909
|
-
const allRegions = [];
|
|
5910
|
-
const allPorts = [];
|
|
5911
|
-
const viaTile = { viasByNet: {}, routeSegments: [] };
|
|
5912
|
-
const gridWidth = cols * tileSize;
|
|
5913
|
-
const gridHeight = rows * tileSize;
|
|
5914
|
-
const gridMinX = bounds.minX + (width - gridWidth) / 2;
|
|
5915
|
-
const gridMinY = bounds.minY + (height - gridHeight) / 2;
|
|
5916
|
-
const gridMaxX = gridMinX + gridWidth;
|
|
5917
|
-
const gridMaxY = gridMinY + gridHeight;
|
|
5918
|
-
const tileGraphs = [];
|
|
5919
|
-
if (rows > 0 && cols > 0) {
|
|
5920
|
-
const baseGraph = generateViaTopologyRegions(inputViaTile, {
|
|
5921
|
-
graphSize: tileSize,
|
|
5922
|
-
idPrefix: "v"
|
|
5923
|
-
});
|
|
5924
|
-
const half = tileSize / 2;
|
|
5925
|
-
const outerIds = ["T", "B", "L", "R"];
|
|
5926
|
-
const baseBoundarySegs = {};
|
|
5927
|
-
for (const id of outerIds) {
|
|
5928
|
-
const r = baseGraph.regions.find((r2) => r2.regionId === `v:${id}`);
|
|
5929
|
-
baseBoundarySegs[id] = {
|
|
5930
|
-
right: getBoundarySegments(r.d.polygon, "right", half),
|
|
5931
|
-
left: getBoundarySegments(r.d.polygon, "left", -half),
|
|
5932
|
-
top: getBoundarySegments(r.d.polygon, "top", half),
|
|
5933
|
-
bottom: getBoundarySegments(r.d.polygon, "bottom", -half)
|
|
5934
|
-
};
|
|
5935
|
-
}
|
|
5936
|
-
for (let row = 0; row < rows; row++) {
|
|
5937
|
-
tileGraphs[row] = [];
|
|
5938
|
-
for (let col = 0; col < cols; col++) {
|
|
5939
|
-
const tileCenterX = gridMinX + col * tileSize + half;
|
|
5940
|
-
const tileCenterY = gridMinY + row * tileSize + half;
|
|
5941
|
-
const prefix = `t${row}_${col}`;
|
|
5942
|
-
const tile = translateGraph(baseGraph, tileCenterX, tileCenterY, prefix);
|
|
5943
|
-
tileGraphs[row][col] = tile;
|
|
5944
|
-
allRegions.push(...tile.regions);
|
|
5945
|
-
allPorts.push(...tile.ports);
|
|
5946
|
-
for (const [netName, vias] of Object.entries(viasByNet)) {
|
|
5947
|
-
if (!viaTile.viasByNet[netName]) {
|
|
5948
|
-
viaTile.viasByNet[netName] = [];
|
|
5949
|
-
}
|
|
5950
|
-
for (const via of vias) {
|
|
5951
|
-
viaTile.viasByNet[netName].push({
|
|
5952
|
-
viaId: `${prefix}:${via.viaId}`,
|
|
5953
|
-
diameter: via.diameter,
|
|
5954
|
-
position: {
|
|
5955
|
-
x: via.position.x + tileCenterX,
|
|
5956
|
-
y: via.position.y + tileCenterY
|
|
5957
|
-
}
|
|
5958
|
-
});
|
|
5959
|
-
}
|
|
5960
|
-
}
|
|
5961
|
-
viaTile.routeSegments.push(
|
|
5962
|
-
...translateRouteSegments(
|
|
5963
|
-
routeSegments,
|
|
5964
|
-
tileCenterX,
|
|
5965
|
-
tileCenterY,
|
|
5966
|
-
prefix
|
|
5967
|
-
)
|
|
5968
|
-
);
|
|
5969
|
-
}
|
|
5970
|
-
}
|
|
5971
|
-
const hPairs = [
|
|
5972
|
-
{
|
|
5973
|
-
leftRegionId: "T",
|
|
5974
|
-
leftEdge: "right",
|
|
5975
|
-
rightRegionId: "T",
|
|
5976
|
-
rightEdge: "left"
|
|
5977
|
-
},
|
|
5978
|
-
{
|
|
5979
|
-
leftRegionId: "R",
|
|
5980
|
-
leftEdge: "right",
|
|
5981
|
-
rightRegionId: "L",
|
|
5982
|
-
rightEdge: "left"
|
|
5983
|
-
},
|
|
5984
|
-
{
|
|
5985
|
-
leftRegionId: "B",
|
|
5986
|
-
leftEdge: "right",
|
|
5987
|
-
rightRegionId: "B",
|
|
5988
|
-
rightEdge: "left"
|
|
5989
|
-
}
|
|
5990
|
-
];
|
|
5991
|
-
for (let row = 0; row < rows; row++) {
|
|
5992
|
-
for (let col = 0; col < cols - 1; col++) {
|
|
5993
|
-
const leftTile = tileGraphs[row][col];
|
|
5994
|
-
const rightTile = tileGraphs[row][col + 1];
|
|
5995
|
-
const boundaryX = gridMinX + (col + 1) * tileSize;
|
|
5996
|
-
const yOffset = gridMinY + row * tileSize + half;
|
|
5997
|
-
for (const pair of hPairs) {
|
|
5998
|
-
const leftSegs = baseBoundarySegs[pair.leftRegionId][pair.leftEdge];
|
|
5999
|
-
const rightSegs = baseBoundarySegs[pair.rightRegionId][pair.rightEdge];
|
|
6000
|
-
for (const ls of leftSegs) {
|
|
6001
|
-
for (const rs of rightSegs) {
|
|
6002
|
-
const overlap = rangeOverlap(ls, rs);
|
|
6003
|
-
if (!overlap) continue;
|
|
6004
|
-
const r1 = findRegionBySuffix(leftTile, `v:${pair.leftRegionId}`);
|
|
6005
|
-
const r2 = findRegionBySuffix(
|
|
6006
|
-
rightTile,
|
|
6007
|
-
`v:${pair.rightRegionId}`
|
|
6008
|
-
);
|
|
6009
|
-
const tag = `${pair.leftRegionId}${pair.rightRegionId}`;
|
|
6010
|
-
const ports = createBoundaryPorts(
|
|
6011
|
-
`cross:h:${row}_${col}:${tag}`,
|
|
6012
|
-
r1,
|
|
6013
|
-
r2,
|
|
6014
|
-
"vertical",
|
|
6015
|
-
boundaryX,
|
|
6016
|
-
overlap.from + yOffset,
|
|
6017
|
-
overlap.to + yOffset,
|
|
6018
|
-
portPitch
|
|
6019
|
-
);
|
|
6020
|
-
allPorts.push(...ports);
|
|
6021
|
-
}
|
|
6022
|
-
}
|
|
6023
|
-
}
|
|
6024
|
-
}
|
|
6025
|
-
}
|
|
6026
|
-
const vPairs = [
|
|
6027
|
-
{
|
|
6028
|
-
bottomRegionId: "T",
|
|
6029
|
-
bottomEdge: "top",
|
|
6030
|
-
topRegionId: "B",
|
|
6031
|
-
topEdge: "bottom"
|
|
6032
|
-
},
|
|
6033
|
-
{
|
|
6034
|
-
bottomRegionId: "L",
|
|
6035
|
-
bottomEdge: "top",
|
|
6036
|
-
topRegionId: "L",
|
|
6037
|
-
topEdge: "bottom"
|
|
6038
|
-
},
|
|
6039
|
-
{
|
|
6040
|
-
bottomRegionId: "R",
|
|
6041
|
-
bottomEdge: "top",
|
|
6042
|
-
topRegionId: "R",
|
|
6043
|
-
topEdge: "bottom"
|
|
6044
|
-
}
|
|
6045
|
-
];
|
|
6046
|
-
for (let row = 0; row < rows - 1; row++) {
|
|
6047
|
-
for (let col = 0; col < cols; col++) {
|
|
6048
|
-
const bottomTile = tileGraphs[row][col];
|
|
6049
|
-
const topTile = tileGraphs[row + 1][col];
|
|
6050
|
-
const boundaryY = gridMinY + (row + 1) * tileSize;
|
|
6051
|
-
const xOffset = gridMinX + col * tileSize + half;
|
|
6052
|
-
for (const pair of vPairs) {
|
|
6053
|
-
const bottomSegs = baseBoundarySegs[pair.bottomRegionId][pair.bottomEdge];
|
|
6054
|
-
const topSegs = baseBoundarySegs[pair.topRegionId][pair.topEdge];
|
|
6055
|
-
for (const bs of bottomSegs) {
|
|
6056
|
-
for (const ts of topSegs) {
|
|
6057
|
-
const overlap = rangeOverlap(bs, ts);
|
|
6058
|
-
if (!overlap) continue;
|
|
6059
|
-
const r1 = findRegionBySuffix(
|
|
6060
|
-
bottomTile,
|
|
6061
|
-
`v:${pair.bottomRegionId}`
|
|
6062
|
-
);
|
|
6063
|
-
const r2 = findRegionBySuffix(topTile, `v:${pair.topRegionId}`);
|
|
6064
|
-
const tag = `${pair.bottomRegionId}${pair.topRegionId}`;
|
|
6065
|
-
const ports = createBoundaryPorts(
|
|
6066
|
-
`cross:v:${row}_${col}:${tag}`,
|
|
6067
|
-
r1,
|
|
6068
|
-
r2,
|
|
6069
|
-
"horizontal",
|
|
6070
|
-
boundaryY,
|
|
6071
|
-
overlap.from + xOffset,
|
|
6072
|
-
overlap.to + xOffset,
|
|
6073
|
-
portPitch
|
|
6074
|
-
);
|
|
6075
|
-
allPorts.push(...ports);
|
|
6076
|
-
}
|
|
6077
|
-
}
|
|
6078
|
-
}
|
|
6079
|
-
}
|
|
6080
|
-
}
|
|
6081
|
-
}
|
|
6082
|
-
const hasTopGap = bounds.maxY > gridMaxY || rows === 0;
|
|
6083
|
-
const hasBottomGap = bounds.minY < gridMinY || rows === 0;
|
|
6084
|
-
const hasLeftGap = bounds.minX < gridMinX || cols === 0;
|
|
6085
|
-
const hasRightGap = bounds.maxX > gridMaxX || cols === 0;
|
|
6086
|
-
let outerTop = null;
|
|
6087
|
-
let outerBottom = null;
|
|
6088
|
-
let outerLeft = null;
|
|
6089
|
-
let outerRight = null;
|
|
6090
|
-
const frameMinX = cols > 0 ? gridMinX : bounds.minX;
|
|
6091
|
-
const frameMaxX = cols > 0 ? gridMaxX : bounds.maxX;
|
|
6092
|
-
const frameMinY = rows > 0 ? gridMinY : bounds.minY;
|
|
6093
|
-
const frameMaxY = rows > 0 ? gridMaxY : bounds.maxY;
|
|
6094
|
-
if (hasLeftGap && bounds.minX < frameMinX) {
|
|
6095
|
-
outerLeft = createRectRegion(
|
|
6096
|
-
"outer:L",
|
|
6097
|
-
bounds.minX,
|
|
6098
|
-
frameMinX,
|
|
6099
|
-
bounds.minY,
|
|
6100
|
-
bounds.maxY
|
|
6101
|
-
);
|
|
6102
|
-
allRegions.push(outerLeft);
|
|
6103
|
-
}
|
|
6104
|
-
if (hasRightGap && bounds.maxX > frameMaxX) {
|
|
6105
|
-
outerRight = createRectRegion(
|
|
6106
|
-
"outer:R",
|
|
6107
|
-
frameMaxX,
|
|
6108
|
-
bounds.maxX,
|
|
6109
|
-
bounds.minY,
|
|
6110
|
-
bounds.maxY
|
|
6111
|
-
);
|
|
6112
|
-
allRegions.push(outerRight);
|
|
6113
|
-
}
|
|
6114
|
-
if (hasTopGap && bounds.maxY > frameMaxY) {
|
|
6115
|
-
outerTop = createRectRegion(
|
|
6116
|
-
"outer:T",
|
|
6117
|
-
frameMinX,
|
|
6118
|
-
frameMaxX,
|
|
6119
|
-
frameMaxY,
|
|
6120
|
-
bounds.maxY
|
|
6121
|
-
);
|
|
6122
|
-
allRegions.push(outerTop);
|
|
6123
|
-
}
|
|
6124
|
-
if (hasBottomGap && bounds.minY < frameMinY) {
|
|
6125
|
-
outerBottom = createRectRegion(
|
|
6126
|
-
"outer:B",
|
|
6127
|
-
frameMinX,
|
|
6128
|
-
frameMaxX,
|
|
6129
|
-
bounds.minY,
|
|
6130
|
-
frameMinY
|
|
6131
|
-
);
|
|
6132
|
-
allRegions.push(outerBottom);
|
|
6133
|
-
}
|
|
6134
|
-
if (outerTop && outerLeft) {
|
|
6135
|
-
allPorts.push(
|
|
6136
|
-
...createBoundaryPorts(
|
|
6137
|
-
"outer:T-L",
|
|
6138
|
-
outerTop,
|
|
6139
|
-
outerLeft,
|
|
6140
|
-
"vertical",
|
|
6141
|
-
frameMinX,
|
|
6142
|
-
frameMaxY,
|
|
6143
|
-
bounds.maxY,
|
|
6144
|
-
portPitch
|
|
6145
|
-
)
|
|
6146
|
-
);
|
|
6147
|
-
}
|
|
6148
|
-
if (outerTop && outerRight) {
|
|
6149
|
-
allPorts.push(
|
|
6150
|
-
...createBoundaryPorts(
|
|
6151
|
-
"outer:T-R",
|
|
6152
|
-
outerTop,
|
|
6153
|
-
outerRight,
|
|
6154
|
-
"vertical",
|
|
6155
|
-
frameMaxX,
|
|
6156
|
-
frameMaxY,
|
|
6157
|
-
bounds.maxY,
|
|
6158
|
-
portPitch
|
|
6159
|
-
)
|
|
6160
|
-
);
|
|
6161
|
-
}
|
|
6162
|
-
if (outerBottom && outerLeft) {
|
|
6163
|
-
allPorts.push(
|
|
6164
|
-
...createBoundaryPorts(
|
|
6165
|
-
"outer:B-L",
|
|
6166
|
-
outerBottom,
|
|
6167
|
-
outerLeft,
|
|
6168
|
-
"vertical",
|
|
6169
|
-
frameMinX,
|
|
6170
|
-
bounds.minY,
|
|
6171
|
-
frameMinY,
|
|
6172
|
-
portPitch
|
|
6173
|
-
)
|
|
6174
|
-
);
|
|
6175
|
-
}
|
|
6176
|
-
if (outerBottom && outerRight) {
|
|
6177
|
-
allPorts.push(
|
|
6178
|
-
...createBoundaryPorts(
|
|
6179
|
-
"outer:B-R",
|
|
6180
|
-
outerBottom,
|
|
6181
|
-
outerRight,
|
|
6182
|
-
"vertical",
|
|
6183
|
-
frameMaxX,
|
|
6184
|
-
bounds.minY,
|
|
6185
|
-
frameMinY,
|
|
6186
|
-
portPitch
|
|
6187
|
-
)
|
|
6188
|
-
);
|
|
6189
|
-
}
|
|
6190
|
-
if (rows > 0 && cols > 0) {
|
|
6191
|
-
const half = tileSize / 2;
|
|
6192
|
-
if (outerTop) {
|
|
6193
|
-
for (let col = 0; col < cols; col++) {
|
|
6194
|
-
const tile = tileGraphs[rows - 1][col];
|
|
6195
|
-
const tileT = findRegionBySuffix(tile, "v:T");
|
|
6196
|
-
const baseT = generateViaTopologyRegions(inputViaTile, {
|
|
6197
|
-
graphSize: tileSize,
|
|
6198
|
-
idPrefix: "v"
|
|
6199
|
-
}).regions.find((r) => r.regionId === "v:T");
|
|
6200
|
-
const topSegs = getBoundarySegments(baseT.d.polygon, "top", half);
|
|
6201
|
-
for (const seg of topSegs) {
|
|
6202
|
-
const tileCenterX = gridMinX + col * tileSize + half;
|
|
6203
|
-
allPorts.push(
|
|
6204
|
-
...createBoundaryPorts(
|
|
6205
|
-
`outer:T-tile${col}`,
|
|
6206
|
-
outerTop,
|
|
6207
|
-
tileT,
|
|
6208
|
-
"horizontal",
|
|
6209
|
-
gridMaxY,
|
|
6210
|
-
seg.from + tileCenterX,
|
|
6211
|
-
seg.to + tileCenterX,
|
|
6212
|
-
portPitch
|
|
6213
|
-
)
|
|
6214
|
-
);
|
|
6215
|
-
}
|
|
6216
|
-
}
|
|
6217
|
-
}
|
|
6218
|
-
if (outerBottom) {
|
|
6219
|
-
for (let col = 0; col < cols; col++) {
|
|
6220
|
-
const tile = tileGraphs[0][col];
|
|
6221
|
-
const tileB = findRegionBySuffix(tile, "v:B");
|
|
6222
|
-
const baseB = generateViaTopologyRegions(inputViaTile, {
|
|
6223
|
-
graphSize: tileSize,
|
|
6224
|
-
idPrefix: "v"
|
|
6225
|
-
}).regions.find((r) => r.regionId === "v:B");
|
|
6226
|
-
const bottomSegs = getBoundarySegments(
|
|
6227
|
-
baseB.d.polygon,
|
|
6228
|
-
"bottom",
|
|
6229
|
-
-half
|
|
6230
|
-
);
|
|
6231
|
-
for (const seg of bottomSegs) {
|
|
6232
|
-
const tileCenterX = gridMinX + col * tileSize + half;
|
|
6233
|
-
allPorts.push(
|
|
6234
|
-
...createBoundaryPorts(
|
|
6235
|
-
`outer:B-tile${col}`,
|
|
6236
|
-
outerBottom,
|
|
6237
|
-
tileB,
|
|
6238
|
-
"horizontal",
|
|
6239
|
-
gridMinY,
|
|
6240
|
-
seg.from + tileCenterX,
|
|
6241
|
-
seg.to + tileCenterX,
|
|
6242
|
-
portPitch
|
|
6243
|
-
)
|
|
6244
|
-
);
|
|
6245
|
-
}
|
|
6246
|
-
}
|
|
6247
|
-
}
|
|
6248
|
-
if (outerLeft) {
|
|
6249
|
-
for (let row = 0; row < rows; row++) {
|
|
6250
|
-
const tile = tileGraphs[row][0];
|
|
6251
|
-
const tileL = findRegionBySuffix(tile, "v:L");
|
|
6252
|
-
const baseL = generateViaTopologyRegions(inputViaTile, {
|
|
6253
|
-
graphSize: tileSize,
|
|
6254
|
-
idPrefix: "v"
|
|
6255
|
-
}).regions.find((r) => r.regionId === "v:L");
|
|
6256
|
-
const leftSegs = getBoundarySegments(baseL.d.polygon, "left", -half);
|
|
6257
|
-
for (const seg of leftSegs) {
|
|
6258
|
-
const tileCenterY = gridMinY + row * tileSize + half;
|
|
6259
|
-
allPorts.push(
|
|
6260
|
-
...createBoundaryPorts(
|
|
6261
|
-
`outer:L-tile${row}`,
|
|
6262
|
-
outerLeft,
|
|
6263
|
-
tileL,
|
|
6264
|
-
"vertical",
|
|
6265
|
-
gridMinX,
|
|
6266
|
-
seg.from + tileCenterY,
|
|
6267
|
-
seg.to + tileCenterY,
|
|
6268
|
-
portPitch
|
|
6269
|
-
)
|
|
6270
|
-
);
|
|
6271
|
-
}
|
|
6272
|
-
}
|
|
6273
|
-
}
|
|
6274
|
-
if (outerRight) {
|
|
6275
|
-
for (let row = 0; row < rows; row++) {
|
|
6276
|
-
const tile = tileGraphs[row][cols - 1];
|
|
6277
|
-
const tileR = findRegionBySuffix(tile, "v:R");
|
|
6278
|
-
const baseR = generateViaTopologyRegions(inputViaTile, {
|
|
6279
|
-
graphSize: tileSize,
|
|
6280
|
-
idPrefix: "v"
|
|
6281
|
-
}).regions.find((r) => r.regionId === "v:R");
|
|
6282
|
-
const rightSegs = getBoundarySegments(baseR.d.polygon, "right", half);
|
|
6283
|
-
for (const seg of rightSegs) {
|
|
6284
|
-
const tileCenterY = gridMinY + row * tileSize + half;
|
|
6285
|
-
allPorts.push(
|
|
6286
|
-
...createBoundaryPorts(
|
|
6287
|
-
`outer:R-tile${row}`,
|
|
6288
|
-
outerRight,
|
|
6289
|
-
tileR,
|
|
6290
|
-
"vertical",
|
|
6291
|
-
gridMaxX,
|
|
6292
|
-
seg.from + tileCenterY,
|
|
6293
|
-
seg.to + tileCenterY,
|
|
6294
|
-
portPitch
|
|
6295
|
-
)
|
|
6296
|
-
);
|
|
6297
|
-
}
|
|
6298
|
-
}
|
|
6299
|
-
}
|
|
6300
|
-
if (outerLeft) {
|
|
6301
|
-
const baseGraph = generateViaTopologyRegions(inputViaTile, {
|
|
6302
|
-
graphSize: tileSize,
|
|
6303
|
-
idPrefix: "v"
|
|
6304
|
-
});
|
|
6305
|
-
const baseT = baseGraph.regions.find((r) => r.regionId === "v:T");
|
|
6306
|
-
const baseB = baseGraph.regions.find((r) => r.regionId === "v:B");
|
|
6307
|
-
const tLeftSegs = getBoundarySegments(baseT.d.polygon, "left", -half);
|
|
6308
|
-
const bLeftSegs = getBoundarySegments(baseB.d.polygon, "left", -half);
|
|
6309
|
-
for (let row = 0; row < rows; row++) {
|
|
6310
|
-
const tile = tileGraphs[row][0];
|
|
6311
|
-
const tileT = findRegionBySuffix(tile, "v:T");
|
|
6312
|
-
const tileB = findRegionBySuffix(tile, "v:B");
|
|
6313
|
-
const tileCenterY = gridMinY + row * tileSize + half;
|
|
6314
|
-
for (const seg of tLeftSegs) {
|
|
6315
|
-
allPorts.push(
|
|
6316
|
-
...createBoundaryPorts(
|
|
6317
|
-
`outer:L-tileT${row}`,
|
|
6318
|
-
outerLeft,
|
|
6319
|
-
tileT,
|
|
6320
|
-
"vertical",
|
|
6321
|
-
gridMinX,
|
|
6322
|
-
seg.from + tileCenterY,
|
|
6323
|
-
seg.to + tileCenterY,
|
|
6324
|
-
portPitch
|
|
6325
|
-
)
|
|
6326
|
-
);
|
|
6327
|
-
}
|
|
6328
|
-
for (const seg of bLeftSegs) {
|
|
6329
|
-
allPorts.push(
|
|
6330
|
-
...createBoundaryPorts(
|
|
6331
|
-
`outer:L-tileB${row}`,
|
|
6332
|
-
outerLeft,
|
|
6333
|
-
tileB,
|
|
6334
|
-
"vertical",
|
|
6335
|
-
gridMinX,
|
|
6336
|
-
seg.from + tileCenterY,
|
|
6337
|
-
seg.to + tileCenterY,
|
|
6338
|
-
portPitch
|
|
6339
|
-
)
|
|
6340
|
-
);
|
|
6341
|
-
}
|
|
6342
|
-
}
|
|
6343
|
-
}
|
|
6344
|
-
if (outerRight) {
|
|
6345
|
-
const baseGraph = generateViaTopologyRegions(inputViaTile, {
|
|
6346
|
-
graphSize: tileSize,
|
|
6347
|
-
idPrefix: "v"
|
|
6348
|
-
});
|
|
6349
|
-
const baseT = baseGraph.regions.find((r) => r.regionId === "v:T");
|
|
6350
|
-
const baseB = baseGraph.regions.find((r) => r.regionId === "v:B");
|
|
6351
|
-
const tRightSegs = getBoundarySegments(baseT.d.polygon, "right", half);
|
|
6352
|
-
const bRightSegs = getBoundarySegments(baseB.d.polygon, "right", half);
|
|
6353
|
-
for (let row = 0; row < rows; row++) {
|
|
6354
|
-
const tile = tileGraphs[row][cols - 1];
|
|
6355
|
-
const tileT = findRegionBySuffix(tile, "v:T");
|
|
6356
|
-
const tileB = findRegionBySuffix(tile, "v:B");
|
|
6357
|
-
const tileCenterY = gridMinY + row * tileSize + half;
|
|
6358
|
-
for (const seg of tRightSegs) {
|
|
6359
|
-
allPorts.push(
|
|
6360
|
-
...createBoundaryPorts(
|
|
6361
|
-
`outer:R-tileT${row}`,
|
|
6362
|
-
outerRight,
|
|
6363
|
-
tileT,
|
|
6364
|
-
"vertical",
|
|
6365
|
-
gridMaxX,
|
|
6366
|
-
seg.from + tileCenterY,
|
|
6367
|
-
seg.to + tileCenterY,
|
|
6368
|
-
portPitch
|
|
6369
|
-
)
|
|
6370
|
-
);
|
|
6371
|
-
}
|
|
6372
|
-
for (const seg of bRightSegs) {
|
|
6373
|
-
allPorts.push(
|
|
6374
|
-
...createBoundaryPorts(
|
|
6375
|
-
`outer:R-tileB${row}`,
|
|
6376
|
-
outerRight,
|
|
6377
|
-
tileB,
|
|
6378
|
-
"vertical",
|
|
6379
|
-
gridMaxX,
|
|
6380
|
-
seg.from + tileCenterY,
|
|
6381
|
-
seg.to + tileCenterY,
|
|
6382
|
-
portPitch
|
|
6383
|
-
)
|
|
6384
|
-
);
|
|
6385
|
-
}
|
|
6386
|
-
}
|
|
6387
|
-
}
|
|
6388
|
-
} else {
|
|
6389
|
-
if (outerTop && outerBottom) {
|
|
6390
|
-
}
|
|
6391
|
-
if (outerLeft && outerRight) {
|
|
6392
|
-
}
|
|
6393
|
-
}
|
|
6394
|
-
return {
|
|
6395
|
-
regions: allRegions,
|
|
6396
|
-
ports: allPorts,
|
|
6397
|
-
viaTile,
|
|
6398
|
-
tileCount: { rows, cols }
|
|
6399
|
-
};
|
|
6400
|
-
}
|
|
6401
|
-
|
|
6402
5775
|
// lib/ViaGraphSolver/defaultTopology.ts
|
|
6403
5776
|
function generateDefaultViaTopologyRegions(opts) {
|
|
6404
5777
|
return generateViaTopologyRegions(via_tile_4_regions_default, opts);
|
|
6405
5778
|
}
|
|
6406
|
-
function generateDefaultViaTopologyGrid(opts) {
|
|
6407
|
-
return generateViaTopologyGrid({
|
|
6408
|
-
...opts,
|
|
6409
|
-
viaTile: via_tile_4_regions_default
|
|
6410
|
-
});
|
|
6411
|
-
}
|
|
6412
5779
|
|
|
6413
5780
|
// lib/ViaGraphSolver/polygonPerimeterUtils.ts
|
|
5781
|
+
function lineSegmentsIntersect(p1, p2, p3, p4, eps = 1e-9) {
|
|
5782
|
+
const pointsCoincident = (a, b) => Math.abs(a.x - b.x) < eps && Math.abs(a.y - b.y) < eps;
|
|
5783
|
+
if (pointsCoincident(p1, p3) || pointsCoincident(p1, p4) || pointsCoincident(p2, p3) || pointsCoincident(p2, p4)) {
|
|
5784
|
+
return false;
|
|
5785
|
+
}
|
|
5786
|
+
const cross2 = (o, a, b) => (a.x - o.x) * (b.y - o.y) - (a.y - o.y) * (b.x - o.x);
|
|
5787
|
+
const d1 = cross2(p3, p4, p1);
|
|
5788
|
+
const d2 = cross2(p3, p4, p2);
|
|
5789
|
+
const d3 = cross2(p1, p2, p3);
|
|
5790
|
+
const d4 = cross2(p1, p2, p4);
|
|
5791
|
+
if (d1 * d2 < 0 && d3 * d4 < 0) {
|
|
5792
|
+
return true;
|
|
5793
|
+
}
|
|
5794
|
+
return false;
|
|
5795
|
+
}
|
|
5796
|
+
function chordsIntersect(newChord, existingChord, perimeter, newPort1, newPort2, existingPort1, existingPort2) {
|
|
5797
|
+
if (chordsCross(newChord, existingChord, perimeter)) {
|
|
5798
|
+
return true;
|
|
5799
|
+
}
|
|
5800
|
+
return lineSegmentsIntersect(
|
|
5801
|
+
newPort1.d,
|
|
5802
|
+
newPort2.d,
|
|
5803
|
+
existingPort1.d,
|
|
5804
|
+
existingPort2.d
|
|
5805
|
+
);
|
|
5806
|
+
}
|
|
6414
5807
|
function computeDifferentNetCrossingsForPolygon(region, port1, port2) {
|
|
6415
5808
|
const polygon2 = region.d.polygon;
|
|
6416
5809
|
if (!polygon2 || polygon2.length < 3) {
|
|
@@ -6423,16 +5816,20 @@ function computeDifferentNetCrossingsForPolygon(region, port1, port2) {
|
|
|
6423
5816
|
let crossings = 0;
|
|
6424
5817
|
const assignments = region.assignments ?? [];
|
|
6425
5818
|
for (const assignment of assignments) {
|
|
6426
|
-
const
|
|
6427
|
-
|
|
6428
|
-
|
|
6429
|
-
);
|
|
6430
|
-
const existingT2 = getPortPerimeterTInRegion(
|
|
6431
|
-
assignment.regionPort2,
|
|
6432
|
-
region
|
|
6433
|
-
);
|
|
5819
|
+
const existingPort1 = assignment.regionPort1;
|
|
5820
|
+
const existingPort2 = assignment.regionPort2;
|
|
5821
|
+
const existingT1 = getPortPerimeterTInRegion(existingPort1, region);
|
|
5822
|
+
const existingT2 = getPortPerimeterTInRegion(existingPort2, region);
|
|
6434
5823
|
const existingChord = [existingT1, existingT2];
|
|
6435
|
-
if (
|
|
5824
|
+
if (chordsIntersect(
|
|
5825
|
+
newChord,
|
|
5826
|
+
existingChord,
|
|
5827
|
+
perimeter,
|
|
5828
|
+
port1,
|
|
5829
|
+
port2,
|
|
5830
|
+
existingPort1,
|
|
5831
|
+
existingPort2
|
|
5832
|
+
)) {
|
|
6436
5833
|
crossings++;
|
|
6437
5834
|
}
|
|
6438
5835
|
}
|
|
@@ -6450,16 +5847,20 @@ function computeCrossingAssignmentsForPolygon(region, port1, port2) {
|
|
|
6450
5847
|
const crossingAssignments = [];
|
|
6451
5848
|
const assignments = region.assignments ?? [];
|
|
6452
5849
|
for (const assignment of assignments) {
|
|
6453
|
-
const
|
|
6454
|
-
|
|
6455
|
-
|
|
6456
|
-
);
|
|
6457
|
-
const existingT2 = getPortPerimeterTInRegion(
|
|
6458
|
-
assignment.regionPort2,
|
|
6459
|
-
region
|
|
6460
|
-
);
|
|
5850
|
+
const existingPort1 = assignment.regionPort1;
|
|
5851
|
+
const existingPort2 = assignment.regionPort2;
|
|
5852
|
+
const existingT1 = getPortPerimeterTInRegion(existingPort1, region);
|
|
5853
|
+
const existingT2 = getPortPerimeterTInRegion(existingPort2, region);
|
|
6461
5854
|
const existingChord = [existingT1, existingT2];
|
|
6462
|
-
if (
|
|
5855
|
+
if (chordsIntersect(
|
|
5856
|
+
newChord,
|
|
5857
|
+
existingChord,
|
|
5858
|
+
perimeter,
|
|
5859
|
+
port1,
|
|
5860
|
+
port2,
|
|
5861
|
+
existingPort1,
|
|
5862
|
+
existingPort2
|
|
5863
|
+
)) {
|
|
6463
5864
|
crossingAssignments.push(assignment);
|
|
6464
5865
|
}
|
|
6465
5866
|
}
|
|
@@ -16296,7 +15697,7 @@ function projectOntoSegment(p, a, b) {
|
|
|
16296
15697
|
const distance3 = Math.sqrt((p.x - closestX) ** 2 + (p.y - closestY) ** 2);
|
|
16297
15698
|
return { t, distance: distance3 };
|
|
16298
15699
|
}
|
|
16299
|
-
function
|
|
15700
|
+
function rangeOverlap(t1Start, t1End, t2Start, t2End) {
|
|
16300
15701
|
const min1 = Math.min(t1Start, t1End);
|
|
16301
15702
|
const max1 = Math.max(t1Start, t1End);
|
|
16302
15703
|
const min2 = Math.min(t2Start, t2End);
|
|
@@ -16318,7 +15719,7 @@ function findSharedEdges(polygon1, polygon2, tolerance = 0.01) {
|
|
|
16318
15719
|
const proj1 = projectOntoSegment(b1, a1, a2);
|
|
16319
15720
|
const proj2 = projectOntoSegment(b2, a1, a2);
|
|
16320
15721
|
if (proj1.distance > tolerance || proj2.distance > tolerance) continue;
|
|
16321
|
-
const overlap =
|
|
15722
|
+
const overlap = rangeOverlap(0, 1, proj1.t, proj2.t);
|
|
16322
15723
|
if (!overlap) continue;
|
|
16323
15724
|
const dx = a2.x - a1.x;
|
|
16324
15725
|
const dy = a2.y - a1.y;
|
|
@@ -16330,10 +15731,7 @@ function findSharedEdges(polygon1, polygon2, tolerance = 0.01) {
|
|
|
16330
15731
|
x: a1.x + overlap.to * dx,
|
|
16331
15732
|
y: a1.y + overlap.to * dy
|
|
16332
15733
|
};
|
|
16333
|
-
|
|
16334
|
-
if (edgeLen > tolerance) {
|
|
16335
|
-
sharedEdges.push({ from, to });
|
|
16336
|
-
}
|
|
15734
|
+
sharedEdges.push({ from, to });
|
|
16337
15735
|
}
|
|
16338
15736
|
}
|
|
16339
15737
|
return sharedEdges;
|
|
@@ -16356,9 +15754,7 @@ function createPortsAlongEdge(edge, portPitch = 0.4) {
|
|
|
16356
15754
|
}
|
|
16357
15755
|
|
|
16358
15756
|
// lib/ViaGraphSolver/via-graph-generator/generateConvexViaTopologyRegions.ts
|
|
16359
|
-
var
|
|
16360
|
-
var DEFAULT_TILE_WIDTH = 3.727;
|
|
16361
|
-
var DEFAULT_TILE_HEIGHT = 4.03;
|
|
15757
|
+
var DEFAULT_PORT_PITCH = 0.4;
|
|
16362
15758
|
var DEFAULT_CLEARANCE = 0.1;
|
|
16363
15759
|
function deduplicateConsecutivePoints(points, tolerance = 1e-3) {
|
|
16364
15760
|
if (points.length <= 1) return points;
|
|
@@ -16403,35 +15799,6 @@ function centroid(points) {
|
|
|
16403
15799
|
}
|
|
16404
15800
|
return { x: cx / points.length, y: cy / points.length };
|
|
16405
15801
|
}
|
|
16406
|
-
function classifySideFromBounds(point2, bounds) {
|
|
16407
|
-
const distances = {
|
|
16408
|
-
left: Math.abs(point2.x - bounds.minX),
|
|
16409
|
-
right: Math.abs(point2.x - bounds.maxX),
|
|
16410
|
-
bottom: Math.abs(point2.y - bounds.minY),
|
|
16411
|
-
top: Math.abs(point2.y - bounds.maxY)
|
|
16412
|
-
};
|
|
16413
|
-
let bestSide = "left";
|
|
16414
|
-
let bestDistance = distances.left;
|
|
16415
|
-
for (const side of ["right", "bottom", "top"]) {
|
|
16416
|
-
if (distances[side] < bestDistance) {
|
|
16417
|
-
bestSide = side;
|
|
16418
|
-
bestDistance = distances[side];
|
|
16419
|
-
}
|
|
16420
|
-
}
|
|
16421
|
-
return bestSide;
|
|
16422
|
-
}
|
|
16423
|
-
function toCandidateKey(regionId, point2) {
|
|
16424
|
-
return `${regionId}:${point2.x.toFixed(6)},${point2.y.toFixed(6)}`;
|
|
16425
|
-
}
|
|
16426
|
-
function compareCandidateQuality(a, b) {
|
|
16427
|
-
if (Math.abs(a.primaryDistance - b.primaryDistance) > 1e-6) {
|
|
16428
|
-
return b.primaryDistance - a.primaryDistance;
|
|
16429
|
-
}
|
|
16430
|
-
if (Math.abs(a.orthDistance - b.orthDistance) > 1e-6) {
|
|
16431
|
-
return a.orthDistance - b.orthDistance;
|
|
16432
|
-
}
|
|
16433
|
-
return a.key < b.key ? -1 : a.key > b.key ? 1 : 0;
|
|
16434
|
-
}
|
|
16435
15802
|
function createRegionFromPolygon(regionId, polygon2, opts) {
|
|
16436
15803
|
const bounds = boundsFromPolygon(polygon2);
|
|
16437
15804
|
return {
|
|
@@ -16502,7 +15869,7 @@ function translateVias(vias, dx, dy, prefix) {
|
|
|
16502
15869
|
}
|
|
16503
15870
|
}));
|
|
16504
15871
|
}
|
|
16505
|
-
function
|
|
15872
|
+
function translateRouteSegments(routeSegments, dx, dy, prefix) {
|
|
16506
15873
|
return routeSegments.map((segment2) => ({
|
|
16507
15874
|
routeId: `${prefix}:${segment2.routeId}`,
|
|
16508
15875
|
fromPort: `${prefix}:${segment2.fromPort}`,
|
|
@@ -16514,10 +15881,133 @@ function translateRouteSegments2(routeSegments, dx, dy, prefix) {
|
|
|
16514
15881
|
}))
|
|
16515
15882
|
}));
|
|
16516
15883
|
}
|
|
15884
|
+
function translatePolygon(polygon2, dx, dy) {
|
|
15885
|
+
return polygon2.map((p) => ({ x: p.x + dx, y: p.y + dy }));
|
|
15886
|
+
}
|
|
15887
|
+
function rectPolygonFromBounds(b) {
|
|
15888
|
+
return [
|
|
15889
|
+
{ x: b.minX, y: b.minY },
|
|
15890
|
+
{ x: b.maxX, y: b.minY },
|
|
15891
|
+
{ x: b.maxX, y: b.maxY },
|
|
15892
|
+
{ x: b.minX, y: b.maxY }
|
|
15893
|
+
];
|
|
15894
|
+
}
|
|
15895
|
+
function extendViaRegionToTileEdge(polygon2, tileBounds, threshold = 0.1) {
|
|
15896
|
+
if (polygon2.length === 0) return polygon2;
|
|
15897
|
+
const polyBounds = boundsFromPolygon(polygon2);
|
|
15898
|
+
const distToLeft = polyBounds.minX - tileBounds.minX;
|
|
15899
|
+
const distToRight = tileBounds.maxX - polyBounds.maxX;
|
|
15900
|
+
const distToBottom = polyBounds.minY - tileBounds.minY;
|
|
15901
|
+
const distToTop = tileBounds.maxY - polyBounds.maxY;
|
|
15902
|
+
const extendLeft = distToLeft > 0 && distToLeft < threshold;
|
|
15903
|
+
const extendRight = distToRight > 0 && distToRight < threshold;
|
|
15904
|
+
const extendBottom = distToBottom > 0 && distToBottom < threshold;
|
|
15905
|
+
const extendTop = distToTop > 0 && distToTop < threshold;
|
|
15906
|
+
if (!extendLeft && !extendRight && !extendBottom && !extendTop) {
|
|
15907
|
+
return polygon2;
|
|
15908
|
+
}
|
|
15909
|
+
const result = polygon2.map((p) => {
|
|
15910
|
+
let x = p.x;
|
|
15911
|
+
let y = p.y;
|
|
15912
|
+
if (extendLeft && Math.abs(p.x - polyBounds.minX) < 1e-3) {
|
|
15913
|
+
x = tileBounds.minX;
|
|
15914
|
+
}
|
|
15915
|
+
if (extendRight && Math.abs(p.x - polyBounds.maxX) < 1e-3) {
|
|
15916
|
+
x = tileBounds.maxX;
|
|
15917
|
+
}
|
|
15918
|
+
if (extendBottom && Math.abs(p.y - polyBounds.minY) < 1e-3) {
|
|
15919
|
+
y = tileBounds.minY;
|
|
15920
|
+
}
|
|
15921
|
+
if (extendTop && Math.abs(p.y - polyBounds.maxY) < 1e-3) {
|
|
15922
|
+
y = tileBounds.maxY;
|
|
15923
|
+
}
|
|
15924
|
+
return { x, y };
|
|
15925
|
+
});
|
|
15926
|
+
return deduplicateConsecutivePoints(result);
|
|
15927
|
+
}
|
|
15928
|
+
function pointInPolygon(point2, polygon2) {
|
|
15929
|
+
let inside2 = false;
|
|
15930
|
+
const n = polygon2.length;
|
|
15931
|
+
for (let i = 0, j = n - 1; i < n; j = i++) {
|
|
15932
|
+
const xi = polygon2[i].x;
|
|
15933
|
+
const yi = polygon2[i].y;
|
|
15934
|
+
const xj = polygon2[j].x;
|
|
15935
|
+
const yj = polygon2[j].y;
|
|
15936
|
+
const onEdge = Math.abs((point2.y - yi) * (xj - xi) - (point2.x - xi) * (yj - yi)) < 1e-3 && point2.x >= Math.min(xi, xj) - 1e-3 && point2.x <= Math.max(xi, xj) + 1e-3 && point2.y >= Math.min(yi, yj) - 1e-3 && point2.y <= Math.max(yi, yj) + 1e-3;
|
|
15937
|
+
if (onEdge) return true;
|
|
15938
|
+
if (yi > point2.y !== yj > point2.y) {
|
|
15939
|
+
const intersectX = (xj - xi) * (point2.y - yi) / (yj - yi) + xi;
|
|
15940
|
+
if (point2.x < intersectX) {
|
|
15941
|
+
inside2 = !inside2;
|
|
15942
|
+
}
|
|
15943
|
+
}
|
|
15944
|
+
}
|
|
15945
|
+
return inside2;
|
|
15946
|
+
}
|
|
15947
|
+
function findRegionContainingPoint(point2, regions) {
|
|
15948
|
+
for (const region of regions) {
|
|
15949
|
+
if (region.d.polygon && pointInPolygon(point2, region.d.polygon)) {
|
|
15950
|
+
return region;
|
|
15951
|
+
}
|
|
15952
|
+
}
|
|
15953
|
+
return null;
|
|
15954
|
+
}
|
|
15955
|
+
function computeUnitTileTemplate(viaTile, tileWidth, tileHeight, clearance, concavityTolerance) {
|
|
15956
|
+
const halfWidth = tileWidth / 2;
|
|
15957
|
+
const halfHeight = tileHeight / 2;
|
|
15958
|
+
const tileBounds = {
|
|
15959
|
+
minX: -halfWidth,
|
|
15960
|
+
maxX: halfWidth,
|
|
15961
|
+
minY: -halfHeight,
|
|
15962
|
+
maxY: halfHeight
|
|
15963
|
+
};
|
|
15964
|
+
const viaRegions = [];
|
|
15965
|
+
for (const [netName, vias] of Object.entries(viaTile.viasByNet)) {
|
|
15966
|
+
if (vias.length === 0) continue;
|
|
15967
|
+
const polygon2 = generateViaRegionPolygon(vias);
|
|
15968
|
+
if (polygon2.length === 0) continue;
|
|
15969
|
+
viaRegions.push({
|
|
15970
|
+
netName,
|
|
15971
|
+
polygon: polygon2,
|
|
15972
|
+
bounds: boundsFromPolygon(polygon2),
|
|
15973
|
+
center: centroid(polygon2)
|
|
15974
|
+
});
|
|
15975
|
+
}
|
|
15976
|
+
const obstaclePolygons = viaRegions.map((r) => ({
|
|
15977
|
+
points: extendViaRegionToTileEdge(r.polygon, tileBounds)
|
|
15978
|
+
}));
|
|
15979
|
+
const solver = new ConvexRegionsSolver({
|
|
15980
|
+
bounds: tileBounds,
|
|
15981
|
+
polygons: obstaclePolygons,
|
|
15982
|
+
clearance,
|
|
15983
|
+
concavityTolerance
|
|
15984
|
+
});
|
|
15985
|
+
solver.solve();
|
|
15986
|
+
const solverOutput = solver.getOutput();
|
|
15987
|
+
if (!solverOutput) {
|
|
15988
|
+
throw new Error("ConvexRegionsSolver failed to compute unit tile regions");
|
|
15989
|
+
}
|
|
15990
|
+
const convexRegions = solverOutput.regions.map((polygon2) => ({
|
|
15991
|
+
polygon: polygon2,
|
|
15992
|
+
bounds: boundsFromPolygon(polygon2),
|
|
15993
|
+
center: centroid(polygon2)
|
|
15994
|
+
}));
|
|
15995
|
+
return {
|
|
15996
|
+
viaRegions,
|
|
15997
|
+
convexRegions,
|
|
15998
|
+
tileWidth,
|
|
15999
|
+
tileHeight
|
|
16000
|
+
};
|
|
16001
|
+
}
|
|
16517
16002
|
function generateConvexViaTopologyRegions(opts) {
|
|
16518
|
-
const tileWidth = opts.tileWidth ?? opts.tileSize ??
|
|
16519
|
-
const tileHeight = opts.tileHeight ?? opts.tileSize ??
|
|
16520
|
-
|
|
16003
|
+
const tileWidth = opts.tileWidth ?? opts.tileSize ?? opts.viaTile.tileWidth;
|
|
16004
|
+
const tileHeight = opts.tileHeight ?? opts.tileSize ?? opts.viaTile.tileHeight;
|
|
16005
|
+
if (tileWidth === void 0 || tileHeight === void 0) {
|
|
16006
|
+
throw new Error(
|
|
16007
|
+
"tileWidth and tileHeight must be provided either in opts or in viaTile"
|
|
16008
|
+
);
|
|
16009
|
+
}
|
|
16010
|
+
const portPitch = opts.portPitch ?? DEFAULT_PORT_PITCH;
|
|
16521
16011
|
const clearance = opts.clearance ?? DEFAULT_CLEARANCE;
|
|
16522
16012
|
const concavityTolerance = opts.concavityTolerance ?? 0;
|
|
16523
16013
|
const { bounds, viaTile: inputViaTile } = opts;
|
|
@@ -16530,18 +16020,79 @@ function generateConvexViaTopologyRegions(opts) {
|
|
|
16530
16020
|
const allPorts = [];
|
|
16531
16021
|
const viaTile = { viasByNet: {}, routeSegments: [] };
|
|
16532
16022
|
const viaRegions = [];
|
|
16023
|
+
const convexRegions = [];
|
|
16533
16024
|
const gridWidth = cols * tileWidth;
|
|
16534
16025
|
const gridHeight = rows * tileHeight;
|
|
16535
16026
|
const gridMinX = bounds.minX + (width - gridWidth) / 2;
|
|
16536
16027
|
const gridMinY = bounds.minY + (height - gridHeight) / 2;
|
|
16028
|
+
const gridMaxX = gridMinX + gridWidth;
|
|
16029
|
+
const gridMaxY = gridMinY + gridHeight;
|
|
16537
16030
|
const halfWidth = tileWidth / 2;
|
|
16538
16031
|
const halfHeight = tileHeight / 2;
|
|
16032
|
+
let portIdCounter = 0;
|
|
16033
|
+
const usedPortPositions = /* @__PURE__ */ new Set();
|
|
16034
|
+
const getPortPosKey = (x, y) => `${x.toFixed(4)},${y.toFixed(4)}`;
|
|
16035
|
+
const createPort = (portId, region1, region2, pos) => {
|
|
16036
|
+
const posKey = getPortPosKey(pos.x, pos.y);
|
|
16037
|
+
if (usedPortPositions.has(posKey)) {
|
|
16038
|
+
return null;
|
|
16039
|
+
}
|
|
16040
|
+
usedPortPositions.add(posKey);
|
|
16041
|
+
const port = {
|
|
16042
|
+
portId,
|
|
16043
|
+
region1,
|
|
16044
|
+
region2,
|
|
16045
|
+
d: { x: pos.x, y: pos.y }
|
|
16046
|
+
};
|
|
16047
|
+
region1.ports.push(port);
|
|
16048
|
+
region2.ports.push(port);
|
|
16049
|
+
allPorts.push(port);
|
|
16050
|
+
return port;
|
|
16051
|
+
};
|
|
16052
|
+
let unitTileTemplate = null;
|
|
16539
16053
|
if (rows > 0 && cols > 0) {
|
|
16054
|
+
unitTileTemplate = computeUnitTileTemplate(
|
|
16055
|
+
inputViaTile,
|
|
16056
|
+
tileWidth,
|
|
16057
|
+
tileHeight,
|
|
16058
|
+
clearance,
|
|
16059
|
+
concavityTolerance
|
|
16060
|
+
);
|
|
16061
|
+
}
|
|
16062
|
+
if (rows > 0 && cols > 0 && unitTileTemplate) {
|
|
16540
16063
|
for (let row = 0; row < rows; row++) {
|
|
16541
16064
|
for (let col = 0; col < cols; col++) {
|
|
16542
16065
|
const tileCenterX = gridMinX + col * tileWidth + halfWidth;
|
|
16543
16066
|
const tileCenterY = gridMinY + row * tileHeight + halfHeight;
|
|
16544
16067
|
const prefix = `t${row}_${col}`;
|
|
16068
|
+
for (const templateViaRegion of unitTileTemplate.viaRegions) {
|
|
16069
|
+
const translatedPolygon = translatePolygon(
|
|
16070
|
+
templateViaRegion.polygon,
|
|
16071
|
+
tileCenterX,
|
|
16072
|
+
tileCenterY
|
|
16073
|
+
);
|
|
16074
|
+
const viaRegion = createRegionFromPolygon(
|
|
16075
|
+
`${prefix}:v:${templateViaRegion.netName}`,
|
|
16076
|
+
translatedPolygon,
|
|
16077
|
+
{ isViaRegion: true }
|
|
16078
|
+
);
|
|
16079
|
+
viaRegions.push(viaRegion);
|
|
16080
|
+
allRegions.push(viaRegion);
|
|
16081
|
+
}
|
|
16082
|
+
for (let i = 0; i < unitTileTemplate.convexRegions.length; i++) {
|
|
16083
|
+
const templateConvexRegion = unitTileTemplate.convexRegions[i];
|
|
16084
|
+
const translatedPolygon = translatePolygon(
|
|
16085
|
+
templateConvexRegion.polygon,
|
|
16086
|
+
tileCenterX,
|
|
16087
|
+
tileCenterY
|
|
16088
|
+
);
|
|
16089
|
+
const convexRegion = createRegionFromPolygon(
|
|
16090
|
+
`${prefix}:convex:${i}`,
|
|
16091
|
+
translatedPolygon
|
|
16092
|
+
);
|
|
16093
|
+
convexRegions.push(convexRegion);
|
|
16094
|
+
allRegions.push(convexRegion);
|
|
16095
|
+
}
|
|
16545
16096
|
for (const [netName, vias] of Object.entries(viasByNet)) {
|
|
16546
16097
|
if (vias.length === 0) continue;
|
|
16547
16098
|
const translatedVias = translateVias(
|
|
@@ -16554,18 +16105,9 @@ function generateConvexViaTopologyRegions(opts) {
|
|
|
16554
16105
|
viaTile.viasByNet[netName] = [];
|
|
16555
16106
|
}
|
|
16556
16107
|
viaTile.viasByNet[netName].push(...translatedVias);
|
|
16557
|
-
const polygon2 = generateViaRegionPolygon(translatedVias);
|
|
16558
|
-
if (polygon2.length === 0) continue;
|
|
16559
|
-
const viaRegion = createRegionFromPolygon(
|
|
16560
|
-
`${prefix}:v:${netName}`,
|
|
16561
|
-
polygon2,
|
|
16562
|
-
{ isViaRegion: true }
|
|
16563
|
-
);
|
|
16564
|
-
viaRegions.push(viaRegion);
|
|
16565
|
-
allRegions.push(viaRegion);
|
|
16566
16108
|
}
|
|
16567
16109
|
viaTile.routeSegments.push(
|
|
16568
|
-
...
|
|
16110
|
+
...translateRouteSegments(
|
|
16569
16111
|
routeSegments,
|
|
16570
16112
|
tileCenterX,
|
|
16571
16113
|
tileCenterY,
|
|
@@ -16575,55 +16117,306 @@ function generateConvexViaTopologyRegions(opts) {
|
|
|
16575
16117
|
}
|
|
16576
16118
|
}
|
|
16577
16119
|
}
|
|
16578
|
-
const
|
|
16579
|
-
|
|
16580
|
-
|
|
16581
|
-
const
|
|
16582
|
-
|
|
16583
|
-
|
|
16584
|
-
|
|
16585
|
-
|
|
16586
|
-
|
|
16587
|
-
const
|
|
16588
|
-
|
|
16589
|
-
const
|
|
16590
|
-
|
|
16591
|
-
|
|
16120
|
+
const fillerRegions = [];
|
|
16121
|
+
const topMargin = bounds.maxY - gridMaxY;
|
|
16122
|
+
const bottomMargin = gridMinY - bounds.minY;
|
|
16123
|
+
const leftMargin = gridMinX - bounds.minX;
|
|
16124
|
+
const rightMargin = bounds.maxX - gridMaxX;
|
|
16125
|
+
const verticalMargin = Math.max(topMargin, bottomMargin);
|
|
16126
|
+
const horizontalMargin = Math.max(leftMargin, rightMargin);
|
|
16127
|
+
const topBottomGetCorners = verticalMargin >= horizontalMargin;
|
|
16128
|
+
const topMinX = topBottomGetCorners ? bounds.minX : gridMinX;
|
|
16129
|
+
const topMaxX = topBottomGetCorners ? bounds.maxX : gridMaxX;
|
|
16130
|
+
const bottomMinX = topBottomGetCorners ? bounds.minX : gridMinX;
|
|
16131
|
+
const bottomMaxX = topBottomGetCorners ? bounds.maxX : gridMaxX;
|
|
16132
|
+
const leftMinY = topBottomGetCorners ? gridMinY : bounds.minY;
|
|
16133
|
+
const leftMaxY = topBottomGetCorners ? gridMaxY : bounds.maxY;
|
|
16134
|
+
const rightMinY = topBottomGetCorners ? gridMinY : bounds.minY;
|
|
16135
|
+
const rightMaxY = topBottomGetCorners ? gridMaxY : bounds.maxY;
|
|
16136
|
+
if (topMargin > 1e-3) {
|
|
16137
|
+
const topWidth = topMaxX - topMinX;
|
|
16138
|
+
const targetStripWidth = Math.max(topMargin, portPitch);
|
|
16139
|
+
const numTopStrips = Math.max(1, Math.floor(topWidth / targetStripWidth));
|
|
16140
|
+
const stripWidth = topWidth / numTopStrips;
|
|
16141
|
+
for (let i = 0; i < numTopStrips; i++) {
|
|
16142
|
+
const fillerBounds = {
|
|
16143
|
+
minX: topMinX + i * stripWidth,
|
|
16144
|
+
maxX: topMinX + (i + 1) * stripWidth,
|
|
16145
|
+
minY: gridMaxY,
|
|
16146
|
+
maxY: bounds.maxY
|
|
16147
|
+
};
|
|
16148
|
+
const regionId = `filler:top:${i}`;
|
|
16149
|
+
const filler = createRegionFromPolygon(
|
|
16150
|
+
regionId,
|
|
16151
|
+
rectPolygonFromBounds(fillerBounds)
|
|
16152
|
+
);
|
|
16153
|
+
fillerRegions.push(filler);
|
|
16154
|
+
allRegions.push(filler);
|
|
16155
|
+
}
|
|
16592
16156
|
}
|
|
16593
|
-
|
|
16594
|
-
|
|
16595
|
-
|
|
16596
|
-
|
|
16597
|
-
|
|
16598
|
-
|
|
16599
|
-
|
|
16600
|
-
|
|
16601
|
-
|
|
16157
|
+
if (bottomMargin > 1e-3) {
|
|
16158
|
+
const bottomWidth = bottomMaxX - bottomMinX;
|
|
16159
|
+
const targetStripWidth = Math.max(bottomMargin, portPitch);
|
|
16160
|
+
const numBottomStrips = Math.max(
|
|
16161
|
+
1,
|
|
16162
|
+
Math.floor(bottomWidth / targetStripWidth)
|
|
16163
|
+
);
|
|
16164
|
+
const stripWidth = bottomWidth / numBottomStrips;
|
|
16165
|
+
for (let i = 0; i < numBottomStrips; i++) {
|
|
16166
|
+
const fillerBounds = {
|
|
16167
|
+
minX: bottomMinX + i * stripWidth,
|
|
16168
|
+
maxX: bottomMinX + (i + 1) * stripWidth,
|
|
16169
|
+
minY: bounds.minY,
|
|
16170
|
+
maxY: gridMinY
|
|
16171
|
+
};
|
|
16172
|
+
const regionId = `filler:bottom:${i}`;
|
|
16173
|
+
const filler = createRegionFromPolygon(
|
|
16174
|
+
regionId,
|
|
16175
|
+
rectPolygonFromBounds(fillerBounds)
|
|
16176
|
+
);
|
|
16177
|
+
fillerRegions.push(filler);
|
|
16178
|
+
allRegions.push(filler);
|
|
16179
|
+
}
|
|
16180
|
+
}
|
|
16181
|
+
if (leftMargin > 1e-3) {
|
|
16182
|
+
const leftHeight = leftMaxY - leftMinY;
|
|
16183
|
+
const targetStripHeight = Math.max(leftMargin, portPitch);
|
|
16184
|
+
const numLeftStrips = Math.max(
|
|
16185
|
+
1,
|
|
16186
|
+
Math.floor(leftHeight / targetStripHeight)
|
|
16187
|
+
);
|
|
16188
|
+
const stripHeight = leftHeight / numLeftStrips;
|
|
16189
|
+
for (let i = 0; i < numLeftStrips; i++) {
|
|
16190
|
+
const fillerBounds = {
|
|
16191
|
+
minX: bounds.minX,
|
|
16192
|
+
maxX: gridMinX,
|
|
16193
|
+
minY: leftMinY + i * stripHeight,
|
|
16194
|
+
maxY: leftMinY + (i + 1) * stripHeight
|
|
16195
|
+
};
|
|
16196
|
+
const regionId = `filler:left:${i}`;
|
|
16197
|
+
const filler = createRegionFromPolygon(
|
|
16198
|
+
regionId,
|
|
16199
|
+
rectPolygonFromBounds(fillerBounds)
|
|
16200
|
+
);
|
|
16201
|
+
fillerRegions.push(filler);
|
|
16202
|
+
allRegions.push(filler);
|
|
16203
|
+
}
|
|
16204
|
+
}
|
|
16205
|
+
if (rightMargin > 1e-3) {
|
|
16206
|
+
const rightHeight = rightMaxY - rightMinY;
|
|
16207
|
+
const targetStripHeight = Math.max(rightMargin, portPitch);
|
|
16208
|
+
const numRightStrips = Math.max(
|
|
16209
|
+
1,
|
|
16210
|
+
Math.floor(rightHeight / targetStripHeight)
|
|
16211
|
+
);
|
|
16212
|
+
const stripHeight = rightHeight / numRightStrips;
|
|
16213
|
+
for (let i = 0; i < numRightStrips; i++) {
|
|
16214
|
+
const fillerBounds = {
|
|
16215
|
+
minX: gridMaxX,
|
|
16216
|
+
maxX: bounds.maxX,
|
|
16217
|
+
minY: rightMinY + i * stripHeight,
|
|
16218
|
+
maxY: rightMinY + (i + 1) * stripHeight
|
|
16219
|
+
};
|
|
16220
|
+
const regionId = `filler:right:${i}`;
|
|
16221
|
+
const filler = createRegionFromPolygon(
|
|
16222
|
+
regionId,
|
|
16223
|
+
rectPolygonFromBounds(fillerBounds)
|
|
16224
|
+
);
|
|
16225
|
+
fillerRegions.push(filler);
|
|
16226
|
+
allRegions.push(filler);
|
|
16227
|
+
}
|
|
16228
|
+
}
|
|
16229
|
+
if (unitTileTemplate && rows > 0 && cols > 0) {
|
|
16230
|
+
const regionsPerTile = unitTileTemplate.convexRegions.length;
|
|
16231
|
+
for (let row = 0; row < rows; row++) {
|
|
16232
|
+
for (let col = 0; col < cols; col++) {
|
|
16233
|
+
const tileIndex = row * cols + col;
|
|
16234
|
+
const tileStartIdx = tileIndex * regionsPerTile;
|
|
16235
|
+
for (let i = 0; i < regionsPerTile; i++) {
|
|
16236
|
+
for (let j = i + 1; j < regionsPerTile; j++) {
|
|
16237
|
+
const region1 = convexRegions[tileStartIdx + i];
|
|
16238
|
+
const region2 = convexRegions[tileStartIdx + j];
|
|
16239
|
+
const sharedEdges = findSharedEdges(
|
|
16240
|
+
region1.d.polygon,
|
|
16241
|
+
region2.d.polygon,
|
|
16242
|
+
clearance * 2
|
|
16243
|
+
);
|
|
16244
|
+
for (const edge of sharedEdges) {
|
|
16245
|
+
const portPositions = createPortsAlongEdge(edge, portPitch);
|
|
16246
|
+
for (const pos of portPositions) {
|
|
16247
|
+
createPort(
|
|
16248
|
+
`t${row}_${col}:convex:${i}-${j}:${portIdCounter++}`,
|
|
16249
|
+
region1,
|
|
16250
|
+
region2,
|
|
16251
|
+
pos
|
|
16252
|
+
);
|
|
16253
|
+
}
|
|
16254
|
+
}
|
|
16255
|
+
}
|
|
16256
|
+
}
|
|
16257
|
+
}
|
|
16258
|
+
}
|
|
16259
|
+
}
|
|
16260
|
+
if (unitTileTemplate && rows > 0 && cols > 0) {
|
|
16261
|
+
const convexPerTile = unitTileTemplate.convexRegions.length;
|
|
16262
|
+
const viasPerTile = unitTileTemplate.viaRegions.length;
|
|
16263
|
+
const numVerticalPorts = Math.floor(tileHeight / portPitch);
|
|
16264
|
+
const verticalPortYOffsets = [];
|
|
16265
|
+
for (let i = 0; i < numVerticalPorts; i++) {
|
|
16266
|
+
verticalPortYOffsets.push(-halfHeight + (i + 0.5) * portPitch);
|
|
16267
|
+
}
|
|
16268
|
+
const numHorizontalPorts = Math.floor(tileWidth / portPitch);
|
|
16269
|
+
const horizontalPortXOffsets = [];
|
|
16270
|
+
for (let i = 0; i < numHorizontalPorts; i++) {
|
|
16271
|
+
horizontalPortXOffsets.push(-halfWidth + (i + 0.5) * portPitch);
|
|
16272
|
+
}
|
|
16273
|
+
for (let row = 0; row < rows; row++) {
|
|
16274
|
+
for (let col = 0; col < cols; col++) {
|
|
16275
|
+
const tileIndex = row * cols + col;
|
|
16276
|
+
const convexStartIdx = tileIndex * convexPerTile;
|
|
16277
|
+
const viaStartIdx = tileIndex * viasPerTile;
|
|
16278
|
+
const tileCenterX = gridMinX + col * tileWidth + halfWidth;
|
|
16279
|
+
const tileCenterY = gridMinY + row * tileHeight + halfHeight;
|
|
16280
|
+
const tileConvexRegions = convexRegions.slice(
|
|
16281
|
+
convexStartIdx,
|
|
16282
|
+
convexStartIdx + convexPerTile
|
|
16283
|
+
);
|
|
16284
|
+
const tileViaRegions = viaRegions.slice(
|
|
16285
|
+
viaStartIdx,
|
|
16286
|
+
viaStartIdx + viasPerTile
|
|
16287
|
+
);
|
|
16288
|
+
const tileAllRegions = [...tileConvexRegions, ...tileViaRegions];
|
|
16289
|
+
if (col + 1 < cols) {
|
|
16290
|
+
const rightTileIndex = row * cols + (col + 1);
|
|
16291
|
+
const rightConvexStartIdx = rightTileIndex * convexPerTile;
|
|
16292
|
+
const rightViaStartIdx = rightTileIndex * viasPerTile;
|
|
16293
|
+
const rightTileConvexRegions = convexRegions.slice(
|
|
16294
|
+
rightConvexStartIdx,
|
|
16295
|
+
rightConvexStartIdx + convexPerTile
|
|
16296
|
+
);
|
|
16297
|
+
const rightTileViaRegions = viaRegions.slice(
|
|
16298
|
+
rightViaStartIdx,
|
|
16299
|
+
rightViaStartIdx + viasPerTile
|
|
16300
|
+
);
|
|
16301
|
+
const rightTileAllRegions = [
|
|
16302
|
+
...rightTileConvexRegions,
|
|
16303
|
+
...rightTileViaRegions
|
|
16304
|
+
];
|
|
16305
|
+
const boundaryX = tileCenterX + halfWidth;
|
|
16306
|
+
for (const yOffset of verticalPortYOffsets) {
|
|
16307
|
+
const portY = tileCenterY + yOffset;
|
|
16308
|
+
const pointInCurrentTile = { x: boundaryX - 0.01, y: portY };
|
|
16309
|
+
const pointInRightTile = { x: boundaryX + 0.01, y: portY };
|
|
16310
|
+
const region1 = findRegionContainingPoint(
|
|
16311
|
+
pointInCurrentTile,
|
|
16312
|
+
tileAllRegions
|
|
16313
|
+
);
|
|
16314
|
+
const region2 = findRegionContainingPoint(
|
|
16315
|
+
pointInRightTile,
|
|
16316
|
+
rightTileAllRegions
|
|
16317
|
+
);
|
|
16318
|
+
if (region1 && region2) {
|
|
16319
|
+
createPort(
|
|
16320
|
+
`tile:${row}_${col}-${row}_${col + 1}:${portIdCounter++}`,
|
|
16321
|
+
region1,
|
|
16322
|
+
region2,
|
|
16323
|
+
{ x: boundaryX, y: portY }
|
|
16324
|
+
);
|
|
16325
|
+
}
|
|
16326
|
+
}
|
|
16327
|
+
}
|
|
16328
|
+
if (row + 1 < rows) {
|
|
16329
|
+
const topTileIndex = (row + 1) * cols + col;
|
|
16330
|
+
const topConvexStartIdx = topTileIndex * convexPerTile;
|
|
16331
|
+
const topViaStartIdx = topTileIndex * viasPerTile;
|
|
16332
|
+
const topTileConvexRegions = convexRegions.slice(
|
|
16333
|
+
topConvexStartIdx,
|
|
16334
|
+
topConvexStartIdx + convexPerTile
|
|
16335
|
+
);
|
|
16336
|
+
const topTileViaRegions = viaRegions.slice(
|
|
16337
|
+
topViaStartIdx,
|
|
16338
|
+
topViaStartIdx + viasPerTile
|
|
16339
|
+
);
|
|
16340
|
+
const topTileAllRegions = [
|
|
16341
|
+
...topTileConvexRegions,
|
|
16342
|
+
...topTileViaRegions
|
|
16343
|
+
];
|
|
16344
|
+
const boundaryY = tileCenterY + halfHeight;
|
|
16345
|
+
for (const xOffset of horizontalPortXOffsets) {
|
|
16346
|
+
const portX = tileCenterX + xOffset;
|
|
16347
|
+
const pointInCurrentTile = { x: portX, y: boundaryY - 0.01 };
|
|
16348
|
+
const pointInTopTile = { x: portX, y: boundaryY + 0.01 };
|
|
16349
|
+
const region1 = findRegionContainingPoint(
|
|
16350
|
+
pointInCurrentTile,
|
|
16351
|
+
tileAllRegions
|
|
16352
|
+
);
|
|
16353
|
+
const region2 = findRegionContainingPoint(
|
|
16354
|
+
pointInTopTile,
|
|
16355
|
+
topTileAllRegions
|
|
16356
|
+
);
|
|
16357
|
+
if (region1 && region2) {
|
|
16358
|
+
createPort(
|
|
16359
|
+
`tile:${row}_${col}-${row + 1}_${col}:${portIdCounter++}`,
|
|
16360
|
+
region1,
|
|
16361
|
+
region2,
|
|
16362
|
+
{ x: portX, y: boundaryY }
|
|
16363
|
+
);
|
|
16364
|
+
}
|
|
16365
|
+
}
|
|
16366
|
+
}
|
|
16367
|
+
}
|
|
16368
|
+
}
|
|
16369
|
+
}
|
|
16370
|
+
for (const fillerRegion of fillerRegions) {
|
|
16371
|
+
const tileRegions = [...convexRegions, ...viaRegions];
|
|
16372
|
+
for (const tileRegion of tileRegions) {
|
|
16373
|
+
const sharedEdges = findSharedEdges(
|
|
16374
|
+
tileRegion.d.polygon,
|
|
16375
|
+
fillerRegion.d.polygon,
|
|
16376
|
+
clearance * 2
|
|
16377
|
+
);
|
|
16378
|
+
for (const edge of sharedEdges) {
|
|
16379
|
+
const portPositions = createPortsAlongEdge(edge, portPitch);
|
|
16380
|
+
for (const pos of portPositions) {
|
|
16381
|
+
createPort(
|
|
16382
|
+
`filler:${tileRegion.regionId}-${fillerRegion.regionId}:${portIdCounter++}`,
|
|
16383
|
+
tileRegion,
|
|
16384
|
+
fillerRegion,
|
|
16385
|
+
pos
|
|
16386
|
+
);
|
|
16387
|
+
}
|
|
16388
|
+
}
|
|
16389
|
+
}
|
|
16390
|
+
}
|
|
16391
|
+
for (let i = 0; i < fillerRegions.length; i++) {
|
|
16392
|
+
for (let j = i + 1; j < fillerRegions.length; j++) {
|
|
16393
|
+
const region1 = fillerRegions[i];
|
|
16394
|
+
const region2 = fillerRegions[j];
|
|
16602
16395
|
const sharedEdges = findSharedEdges(
|
|
16603
16396
|
region1.d.polygon,
|
|
16604
16397
|
region2.d.polygon,
|
|
16605
|
-
|
|
16606
|
-
// tolerance slightly larger than clearance
|
|
16398
|
+
0.01
|
|
16607
16399
|
);
|
|
16608
16400
|
for (const edge of sharedEdges) {
|
|
16401
|
+
const edgeLength = Math.sqrt(
|
|
16402
|
+
(edge.to.x - edge.from.x) ** 2 + (edge.to.y - edge.from.y) ** 2
|
|
16403
|
+
);
|
|
16404
|
+
if (edgeLength < portPitch) {
|
|
16405
|
+
continue;
|
|
16406
|
+
}
|
|
16609
16407
|
const portPositions = createPortsAlongEdge(edge, portPitch);
|
|
16610
16408
|
for (const pos of portPositions) {
|
|
16611
|
-
|
|
16612
|
-
|
|
16409
|
+
createPort(
|
|
16410
|
+
`filler:${region1.regionId}-${region2.regionId}:${portIdCounter++}`,
|
|
16613
16411
|
region1,
|
|
16614
16412
|
region2,
|
|
16615
|
-
|
|
16616
|
-
|
|
16617
|
-
region1.ports.push(port);
|
|
16618
|
-
region2.ports.push(port);
|
|
16619
|
-
allPorts.push(port);
|
|
16413
|
+
pos
|
|
16414
|
+
);
|
|
16620
16415
|
}
|
|
16621
16416
|
}
|
|
16622
16417
|
}
|
|
16623
16418
|
}
|
|
16624
16419
|
for (const viaRegion of viaRegions) {
|
|
16625
|
-
const viaCenter = viaRegion.d.center;
|
|
16626
|
-
const candidates = [];
|
|
16627
16420
|
for (const convexRegion of convexRegions) {
|
|
16628
16421
|
const sharedEdges = findSharedEdges(
|
|
16629
16422
|
viaRegion.d.polygon,
|
|
@@ -16633,55 +16426,15 @@ function generateConvexViaTopologyRegions(opts) {
|
|
|
16633
16426
|
for (const edge of sharedEdges) {
|
|
16634
16427
|
const portPositions = createPortsAlongEdge(edge, portPitch);
|
|
16635
16428
|
for (const pos of portPositions) {
|
|
16636
|
-
|
|
16637
|
-
|
|
16638
|
-
|
|
16639
|
-
const primaryDistance = side === "left" || side === "right" ? Math.abs(dx) : Math.abs(dy);
|
|
16640
|
-
const orthDistance = side === "left" || side === "right" ? Math.abs(dy) : Math.abs(dx);
|
|
16641
|
-
candidates.push({
|
|
16429
|
+
createPort(
|
|
16430
|
+
`via-convex:${viaRegion.regionId}-${convexRegion.regionId}:${portIdCounter++}`,
|
|
16431
|
+
viaRegion,
|
|
16642
16432
|
convexRegion,
|
|
16643
|
-
|
|
16644
|
-
|
|
16645
|
-
primaryDistance,
|
|
16646
|
-
orthDistance,
|
|
16647
|
-
key: toCandidateKey(convexRegion.regionId, pos)
|
|
16648
|
-
});
|
|
16433
|
+
pos
|
|
16434
|
+
);
|
|
16649
16435
|
}
|
|
16650
16436
|
}
|
|
16651
16437
|
}
|
|
16652
|
-
if (candidates.length === 0) continue;
|
|
16653
|
-
const selectedCandidates = [];
|
|
16654
|
-
const selectedKeys = /* @__PURE__ */ new Set();
|
|
16655
|
-
const addCandidate = (candidate) => {
|
|
16656
|
-
if (!candidate) return;
|
|
16657
|
-
if (selectedKeys.has(candidate.key)) return;
|
|
16658
|
-
selectedCandidates.push(candidate);
|
|
16659
|
-
selectedKeys.add(candidate.key);
|
|
16660
|
-
};
|
|
16661
|
-
for (const side of ["top", "bottom", "left", "right"]) {
|
|
16662
|
-
const sideCandidate = [...candidates].filter((candidate) => candidate.side === side).sort(compareCandidateQuality)[0];
|
|
16663
|
-
addCandidate(sideCandidate);
|
|
16664
|
-
}
|
|
16665
|
-
if (selectedCandidates.length < 4) {
|
|
16666
|
-
for (const candidate of [...candidates].sort(compareCandidateQuality)) {
|
|
16667
|
-
addCandidate(candidate);
|
|
16668
|
-
if (selectedCandidates.length >= 4) break;
|
|
16669
|
-
}
|
|
16670
|
-
}
|
|
16671
|
-
for (const selectedCandidate of selectedCandidates.slice(0, 4)) {
|
|
16672
|
-
const port = {
|
|
16673
|
-
portId: `via-convex:${viaRegion.regionId}-${selectedCandidate.convexRegion.regionId}:${portIdCounter++}`,
|
|
16674
|
-
region1: viaRegion,
|
|
16675
|
-
region2: selectedCandidate.convexRegion,
|
|
16676
|
-
d: {
|
|
16677
|
-
x: selectedCandidate.position.x,
|
|
16678
|
-
y: selectedCandidate.position.y
|
|
16679
|
-
}
|
|
16680
|
-
};
|
|
16681
|
-
viaRegion.ports.push(port);
|
|
16682
|
-
selectedCandidate.convexRegion.ports.push(port);
|
|
16683
|
-
allPorts.push(port);
|
|
16684
|
-
}
|
|
16685
16438
|
}
|
|
16686
16439
|
return {
|
|
16687
16440
|
regions: allRegions,
|
|
@@ -16718,8 +16471,8 @@ function createConvexViaGraphFromXYConnections(xyConnections, viaTile = via_tile
|
|
|
16718
16471
|
} = generateConvexViaTopologyRegions({
|
|
16719
16472
|
viaTile,
|
|
16720
16473
|
bounds,
|
|
16721
|
-
tileWidth: opts?.tileWidth,
|
|
16722
|
-
tileHeight: opts?.tileHeight,
|
|
16474
|
+
tileWidth: opts?.tileWidth ?? viaTile.tileWidth,
|
|
16475
|
+
tileHeight: opts?.tileHeight ?? viaTile.tileHeight,
|
|
16723
16476
|
tileSize: opts?.tileSize,
|
|
16724
16477
|
portPitch: opts?.portPitch,
|
|
16725
16478
|
clearance: opts?.clearance,
|
|
@@ -16736,48 +16489,6 @@ function createConvexViaGraphFromXYConnections(xyConnections, viaTile = via_tile
|
|
|
16736
16489
|
tileCount
|
|
16737
16490
|
};
|
|
16738
16491
|
}
|
|
16739
|
-
|
|
16740
|
-
// lib/ViaGraphSolver/via-graph-generator/createViaGraphFromXYConnections.ts
|
|
16741
|
-
function calculateBoundsFromConnections2(xyConnections) {
|
|
16742
|
-
if (xyConnections.length === 0) {
|
|
16743
|
-
throw new Error("Cannot calculate bounds from empty connections array");
|
|
16744
|
-
}
|
|
16745
|
-
let minX = Infinity;
|
|
16746
|
-
let maxX = -Infinity;
|
|
16747
|
-
let minY = Infinity;
|
|
16748
|
-
let maxY = -Infinity;
|
|
16749
|
-
for (const conn of xyConnections) {
|
|
16750
|
-
minX = Math.min(minX, conn.start.x, conn.end.x);
|
|
16751
|
-
maxX = Math.max(maxX, conn.start.x, conn.end.x);
|
|
16752
|
-
minY = Math.min(minY, conn.start.y, conn.end.y);
|
|
16753
|
-
maxY = Math.max(maxY, conn.start.y, conn.end.y);
|
|
16754
|
-
}
|
|
16755
|
-
return { minX, maxX, minY, maxY };
|
|
16756
|
-
}
|
|
16757
|
-
function createViaGraphFromXYConnections(xyConnections, viaTile, opts) {
|
|
16758
|
-
const bounds = calculateBoundsFromConnections2(xyConnections);
|
|
16759
|
-
const {
|
|
16760
|
-
regions,
|
|
16761
|
-
ports,
|
|
16762
|
-
viaTile: generatedViaTile,
|
|
16763
|
-
tileCount
|
|
16764
|
-
} = generateViaTopologyGrid({
|
|
16765
|
-
viaTile,
|
|
16766
|
-
bounds,
|
|
16767
|
-
tileSize: opts?.tileSize,
|
|
16768
|
-
portPitch: opts?.portPitch
|
|
16769
|
-
});
|
|
16770
|
-
const baseGraph = { regions, ports };
|
|
16771
|
-
const graphWithConnections = createViaGraphWithConnections(
|
|
16772
|
-
baseGraph,
|
|
16773
|
-
xyConnections
|
|
16774
|
-
);
|
|
16775
|
-
return {
|
|
16776
|
-
...graphWithConnections,
|
|
16777
|
-
viaTile: generatedViaTile,
|
|
16778
|
-
tileCount
|
|
16779
|
-
};
|
|
16780
|
-
}
|
|
16781
16492
|
export {
|
|
16782
16493
|
ConnectBuilder,
|
|
16783
16494
|
HyperGraphSolver,
|
|
@@ -16795,14 +16506,11 @@ export {
|
|
|
16795
16506
|
convertHyperGraphToSerializedHyperGraph,
|
|
16796
16507
|
createConvexViaGraphFromXYConnections,
|
|
16797
16508
|
createGraphWithConnectionsFromBaseGraph,
|
|
16798
|
-
createViaGraphFromXYConnections,
|
|
16799
16509
|
createViaGraphWithConnections,
|
|
16800
16510
|
generateConvexViaTopologyRegions,
|
|
16801
|
-
generateDefaultViaTopologyGrid,
|
|
16802
16511
|
generateDefaultViaTopologyRegions,
|
|
16803
16512
|
generateJumperGrid,
|
|
16804
16513
|
generateJumperX4Grid,
|
|
16805
|
-
generateViaTopologyGrid,
|
|
16806
16514
|
generateViaTopologyRegions,
|
|
16807
16515
|
rotateGraph90Degrees,
|
|
16808
16516
|
via_tile_4_regions_default as viaTile
|