@tscircuit/hypergraph 0.0.44 → 0.0.46
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 +129 -102
- package/dist/index.js +644 -237
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5237,88 +5237,88 @@ var via_tile_4_regions_default = {
|
|
|
5237
5237
|
net1: [
|
|
5238
5238
|
{
|
|
5239
5239
|
viaId: "14ee4bf1-e7e7-4351-ad16-ba1a8aac0af3",
|
|
5240
|
-
diameter: 0.
|
|
5240
|
+
diameter: 0.3,
|
|
5241
5241
|
position: {
|
|
5242
|
-
x:
|
|
5243
|
-
y: 0.
|
|
5242
|
+
x: 0.815244,
|
|
5243
|
+
y: -0.055081
|
|
5244
5244
|
}
|
|
5245
5245
|
},
|
|
5246
5246
|
{
|
|
5247
5247
|
viaId: "8a898812-db2b-4b81-899d-f953b3222f9a",
|
|
5248
|
-
diameter: 0.
|
|
5248
|
+
diameter: 0.3,
|
|
5249
5249
|
position: {
|
|
5250
|
-
x: -0.
|
|
5251
|
-
y:
|
|
5250
|
+
x: -0.528763,
|
|
5251
|
+
y: 0.676055
|
|
5252
5252
|
}
|
|
5253
5253
|
}
|
|
5254
5254
|
],
|
|
5255
5255
|
net3: [
|
|
5256
5256
|
{
|
|
5257
5257
|
viaId: "13cd75da-d582-4eed-bc2c-fee6fa78bc6a",
|
|
5258
|
-
diameter: 0.
|
|
5258
|
+
diameter: 0.3,
|
|
5259
5259
|
position: {
|
|
5260
|
-
x: -
|
|
5261
|
-
y: -
|
|
5260
|
+
x: -0.808222,
|
|
5261
|
+
y: -0.726499
|
|
5262
5262
|
}
|
|
5263
5263
|
},
|
|
5264
5264
|
{
|
|
5265
5265
|
viaId: "9f188f9d-bce8-46c7-b9e8-542b8599d48d",
|
|
5266
|
-
diameter: 0.
|
|
5266
|
+
diameter: 0.3,
|
|
5267
5267
|
position: {
|
|
5268
|
-
x:
|
|
5269
|
-
y:
|
|
5268
|
+
x: 0.901143,
|
|
5269
|
+
y: 0.437488
|
|
5270
5270
|
}
|
|
5271
5271
|
}
|
|
5272
5272
|
],
|
|
5273
5273
|
net4: [
|
|
5274
5274
|
{
|
|
5275
5275
|
viaId: "2ef3b96b-58c4-4150-b5d1-e90f74b92b25",
|
|
5276
|
-
diameter: 0.
|
|
5276
|
+
diameter: 0.3,
|
|
5277
5277
|
position: {
|
|
5278
|
-
x: -0.
|
|
5279
|
-
y:
|
|
5278
|
+
x: -0.029,
|
|
5279
|
+
y: 0.691542
|
|
5280
5280
|
}
|
|
5281
5281
|
},
|
|
5282
5282
|
{
|
|
5283
5283
|
viaId: "37a70467-7553-415f-8ad7-8b88a5e56ca8",
|
|
5284
|
-
diameter: 0.
|
|
5284
|
+
diameter: 0.3,
|
|
5285
5285
|
position: {
|
|
5286
|
-
x: -
|
|
5287
|
-
y: 0.
|
|
5286
|
+
x: -0.824388,
|
|
5287
|
+
y: 0.272808
|
|
5288
5288
|
}
|
|
5289
5289
|
},
|
|
5290
5290
|
{
|
|
5291
5291
|
viaId: "6d182b7d-a260-427b-8c43-a09409422252",
|
|
5292
|
-
diameter: 0.
|
|
5292
|
+
diameter: 0.3,
|
|
5293
5293
|
position: {
|
|
5294
|
-
x:
|
|
5295
|
-
y: -
|
|
5294
|
+
x: 0.083422,
|
|
5295
|
+
y: -0.705274
|
|
5296
5296
|
}
|
|
5297
5297
|
}
|
|
5298
5298
|
],
|
|
5299
5299
|
net5: [
|
|
5300
5300
|
{
|
|
5301
5301
|
viaId: "346c301a-f2b4-44d7-b975-5438ddaa0bde",
|
|
5302
|
-
diameter: 0.
|
|
5302
|
+
diameter: 0.3,
|
|
5303
5303
|
position: {
|
|
5304
|
-
x: 0.
|
|
5305
|
-
y: -0.
|
|
5304
|
+
x: 0.517145,
|
|
5305
|
+
y: -0.456503
|
|
5306
5306
|
}
|
|
5307
5307
|
},
|
|
5308
5308
|
{
|
|
5309
5309
|
viaId: "c54b4b94-90e0-4240-97ef-883cf097d79d",
|
|
5310
|
-
diameter: 0.
|
|
5310
|
+
diameter: 0.3,
|
|
5311
5311
|
position: {
|
|
5312
|
-
x: 0.
|
|
5313
|
-
y:
|
|
5312
|
+
x: 0.471002,
|
|
5313
|
+
y: 0.692404
|
|
5314
5314
|
}
|
|
5315
5315
|
},
|
|
5316
5316
|
{
|
|
5317
5317
|
viaId: "f3cb916e-b0fd-4c5e-b14b-3779f4f9bd01",
|
|
5318
|
-
diameter: 0.
|
|
5318
|
+
diameter: 0.3,
|
|
5319
5319
|
position: {
|
|
5320
|
-
x: -
|
|
5321
|
-
y: -0.
|
|
5320
|
+
x: -0.833162,
|
|
5321
|
+
y: -0.227118
|
|
5322
5322
|
}
|
|
5323
5323
|
}
|
|
5324
5324
|
]
|
|
@@ -5331,36 +5331,40 @@ var via_tile_4_regions_default = {
|
|
|
5331
5331
|
layer: "bottom",
|
|
5332
5332
|
segments: [
|
|
5333
5333
|
{
|
|
5334
|
-
x:
|
|
5335
|
-
y: 0.
|
|
5334
|
+
x: 0.815244,
|
|
5335
|
+
y: -0.055081
|
|
5336
5336
|
},
|
|
5337
5337
|
{
|
|
5338
|
-
x: 1.
|
|
5339
|
-
y: -0.
|
|
5338
|
+
x: 1.01282,
|
|
5339
|
+
y: -0.252657
|
|
5340
5340
|
},
|
|
5341
5341
|
{
|
|
5342
|
-
x:
|
|
5343
|
-
y: -
|
|
5342
|
+
x: 1.01282,
|
|
5343
|
+
y: -0.563283
|
|
5344
5344
|
},
|
|
5345
5345
|
{
|
|
5346
|
-
x:
|
|
5347
|
-
y: -1.
|
|
5346
|
+
x: 0.444829,
|
|
5347
|
+
y: -1.131274
|
|
5348
5348
|
},
|
|
5349
5349
|
{
|
|
5350
|
-
x: -0.
|
|
5351
|
-
y: -1.
|
|
5350
|
+
x: -0.093033,
|
|
5351
|
+
y: -1.131274
|
|
5352
5352
|
},
|
|
5353
5353
|
{
|
|
5354
|
-
x: -0.
|
|
5355
|
-
y: 0.
|
|
5354
|
+
x: -0.382222,
|
|
5355
|
+
y: -0.842085
|
|
5356
5356
|
},
|
|
5357
5357
|
{
|
|
5358
|
-
x: -0.
|
|
5359
|
-
y: 0.
|
|
5358
|
+
x: -0.382222,
|
|
5359
|
+
y: 0.433097
|
|
5360
5360
|
},
|
|
5361
5361
|
{
|
|
5362
|
-
x: -0.
|
|
5363
|
-
y:
|
|
5362
|
+
x: -0.528763,
|
|
5363
|
+
y: 0.579638
|
|
5364
|
+
},
|
|
5365
|
+
{
|
|
5366
|
+
x: -0.528763,
|
|
5367
|
+
y: 0.676055
|
|
5364
5368
|
}
|
|
5365
5369
|
]
|
|
5366
5370
|
},
|
|
@@ -5371,28 +5375,36 @@ var via_tile_4_regions_default = {
|
|
|
5371
5375
|
layer: "bottom",
|
|
5372
5376
|
segments: [
|
|
5373
5377
|
{
|
|
5374
|
-
x: -
|
|
5375
|
-
y: -
|
|
5378
|
+
x: -0.808222,
|
|
5379
|
+
y: -0.726499
|
|
5380
|
+
},
|
|
5381
|
+
{
|
|
5382
|
+
x: -0.808222,
|
|
5383
|
+
y: -0.912474
|
|
5376
5384
|
},
|
|
5377
5385
|
{
|
|
5378
|
-
x: -0.
|
|
5379
|
-
y: -1.
|
|
5386
|
+
x: -0.238422,
|
|
5387
|
+
y: -1.482274
|
|
5380
5388
|
},
|
|
5381
5389
|
{
|
|
5382
|
-
x: 0.
|
|
5383
|
-
y: -1.
|
|
5390
|
+
x: 0.590217,
|
|
5391
|
+
y: -1.482274
|
|
5384
5392
|
},
|
|
5385
5393
|
{
|
|
5386
|
-
x: 1.
|
|
5387
|
-
y: -0.
|
|
5394
|
+
x: 1.36382,
|
|
5395
|
+
y: -0.708672
|
|
5388
5396
|
},
|
|
5389
5397
|
{
|
|
5390
|
-
x: 1.
|
|
5391
|
-
y:
|
|
5398
|
+
x: 1.36382,
|
|
5399
|
+
y: -1202e-6
|
|
5392
5400
|
},
|
|
5393
5401
|
{
|
|
5394
|
-
x:
|
|
5395
|
-
y:
|
|
5402
|
+
x: 0.92513,
|
|
5403
|
+
y: 0.437488
|
|
5404
|
+
},
|
|
5405
|
+
{
|
|
5406
|
+
x: 0.901143,
|
|
5407
|
+
y: 0.437488
|
|
5396
5408
|
}
|
|
5397
5409
|
]
|
|
5398
5410
|
},
|
|
@@ -5403,16 +5415,16 @@ var via_tile_4_regions_default = {
|
|
|
5403
5415
|
layer: "bottom",
|
|
5404
5416
|
segments: [
|
|
5405
5417
|
{
|
|
5406
|
-
x: -0.
|
|
5407
|
-
y:
|
|
5418
|
+
x: -0.029,
|
|
5419
|
+
y: 0.691542
|
|
5408
5420
|
},
|
|
5409
5421
|
{
|
|
5410
|
-
x: -0.
|
|
5411
|
-
y:
|
|
5422
|
+
x: -0.029,
|
|
5423
|
+
y: -0.592852
|
|
5412
5424
|
},
|
|
5413
5425
|
{
|
|
5414
|
-
x:
|
|
5415
|
-
y: -
|
|
5426
|
+
x: 0.083422,
|
|
5427
|
+
y: -0.705274
|
|
5416
5428
|
}
|
|
5417
5429
|
]
|
|
5418
5430
|
},
|
|
@@ -5423,28 +5435,32 @@ var via_tile_4_regions_default = {
|
|
|
5423
5435
|
layer: "bottom",
|
|
5424
5436
|
segments: [
|
|
5425
5437
|
{
|
|
5426
|
-
x: -0.
|
|
5427
|
-
y:
|
|
5438
|
+
x: -0.029,
|
|
5439
|
+
y: 0.691542
|
|
5440
|
+
},
|
|
5441
|
+
{
|
|
5442
|
+
x: -0.029,
|
|
5443
|
+
y: 0.778747
|
|
5428
5444
|
},
|
|
5429
5445
|
{
|
|
5430
|
-
x: -0.
|
|
5431
|
-
y: 1.
|
|
5446
|
+
x: -0.352308,
|
|
5447
|
+
y: 1.102055
|
|
5432
5448
|
},
|
|
5433
5449
|
{
|
|
5434
|
-
x: -
|
|
5435
|
-
y: 1.
|
|
5450
|
+
x: -0.705218,
|
|
5451
|
+
y: 1.102055
|
|
5436
5452
|
},
|
|
5437
5453
|
{
|
|
5438
|
-
x: -
|
|
5439
|
-
y:
|
|
5454
|
+
x: -0.954763,
|
|
5455
|
+
y: 0.85251
|
|
5440
5456
|
},
|
|
5441
5457
|
{
|
|
5442
|
-
x: -
|
|
5443
|
-
y: 0.
|
|
5458
|
+
x: -0.954763,
|
|
5459
|
+
y: 0.403183
|
|
5444
5460
|
},
|
|
5445
5461
|
{
|
|
5446
|
-
x: -
|
|
5447
|
-
y: 0.
|
|
5462
|
+
x: -0.824388,
|
|
5463
|
+
y: 0.272808
|
|
5448
5464
|
}
|
|
5449
5465
|
]
|
|
5450
5466
|
},
|
|
@@ -5455,20 +5471,20 @@ var via_tile_4_regions_default = {
|
|
|
5455
5471
|
layer: "bottom",
|
|
5456
5472
|
segments: [
|
|
5457
5473
|
{
|
|
5458
|
-
x: 0.
|
|
5459
|
-
y: -0.
|
|
5474
|
+
x: 0.517145,
|
|
5475
|
+
y: -0.456503
|
|
5460
5476
|
},
|
|
5461
5477
|
{
|
|
5462
|
-
x: 0.
|
|
5463
|
-
y:
|
|
5478
|
+
x: 0.389244,
|
|
5479
|
+
y: -0.328602
|
|
5464
5480
|
},
|
|
5465
5481
|
{
|
|
5466
|
-
x: 0.
|
|
5467
|
-
y:
|
|
5482
|
+
x: 0.389244,
|
|
5483
|
+
y: 0.610646
|
|
5468
5484
|
},
|
|
5469
5485
|
{
|
|
5470
|
-
x: 0.
|
|
5471
|
-
y:
|
|
5486
|
+
x: 0.471002,
|
|
5487
|
+
y: 0.692404
|
|
5472
5488
|
}
|
|
5473
5489
|
]
|
|
5474
5490
|
},
|
|
@@ -5479,34 +5495,42 @@ var via_tile_4_regions_default = {
|
|
|
5479
5495
|
layer: "bottom",
|
|
5480
5496
|
segments: [
|
|
5481
5497
|
{
|
|
5482
|
-
x: 0.
|
|
5483
|
-
y:
|
|
5498
|
+
x: 0.471002,
|
|
5499
|
+
y: 0.692404
|
|
5500
|
+
},
|
|
5501
|
+
{
|
|
5502
|
+
x: 0.471002,
|
|
5503
|
+
y: 1.111132
|
|
5484
5504
|
},
|
|
5485
5505
|
{
|
|
5486
|
-
x:
|
|
5487
|
-
y: 1.
|
|
5506
|
+
x: 0.129079,
|
|
5507
|
+
y: 1.453055
|
|
5488
5508
|
},
|
|
5489
5509
|
{
|
|
5490
|
-
x: -
|
|
5491
|
-
y: 1.
|
|
5510
|
+
x: -0.850606,
|
|
5511
|
+
y: 1.453055
|
|
5492
5512
|
},
|
|
5493
5513
|
{
|
|
5494
|
-
x: -1.
|
|
5495
|
-
y:
|
|
5514
|
+
x: -1.305763,
|
|
5515
|
+
y: 0.997899
|
|
5496
5516
|
},
|
|
5497
5517
|
{
|
|
5498
|
-
x: -1.
|
|
5499
|
-
y: 0.
|
|
5518
|
+
x: -1.305763,
|
|
5519
|
+
y: 0.151728
|
|
5500
5520
|
},
|
|
5501
5521
|
{
|
|
5502
|
-
x: -
|
|
5503
|
-
y: -0.
|
|
5522
|
+
x: -0.926917,
|
|
5523
|
+
y: -0.227118
|
|
5524
|
+
},
|
|
5525
|
+
{
|
|
5526
|
+
x: -0.833162,
|
|
5527
|
+
y: -0.227118
|
|
5504
5528
|
}
|
|
5505
5529
|
]
|
|
5506
5530
|
}
|
|
5507
5531
|
],
|
|
5508
|
-
tileWidth:
|
|
5509
|
-
tileHeight:
|
|
5532
|
+
tileWidth: 2.9695829999999996,
|
|
5533
|
+
tileHeight: 3.2353289999999997
|
|
5510
5534
|
};
|
|
5511
5535
|
|
|
5512
5536
|
// lib/ViaGraphSolver/via-graph-generator/generateViaTopologyRegions.ts
|
|
@@ -5778,6 +5802,32 @@ function generateDefaultViaTopologyRegions(opts) {
|
|
|
5778
5802
|
}
|
|
5779
5803
|
|
|
5780
5804
|
// lib/ViaGraphSolver/polygonPerimeterUtils.ts
|
|
5805
|
+
function lineSegmentsIntersect(p1, p2, p3, p4, eps = 1e-9) {
|
|
5806
|
+
const pointsCoincident = (a, b) => Math.abs(a.x - b.x) < eps && Math.abs(a.y - b.y) < eps;
|
|
5807
|
+
if (pointsCoincident(p1, p3) || pointsCoincident(p1, p4) || pointsCoincident(p2, p3) || pointsCoincident(p2, p4)) {
|
|
5808
|
+
return false;
|
|
5809
|
+
}
|
|
5810
|
+
const cross2 = (o, a, b) => (a.x - o.x) * (b.y - o.y) - (a.y - o.y) * (b.x - o.x);
|
|
5811
|
+
const d1 = cross2(p3, p4, p1);
|
|
5812
|
+
const d2 = cross2(p3, p4, p2);
|
|
5813
|
+
const d3 = cross2(p1, p2, p3);
|
|
5814
|
+
const d4 = cross2(p1, p2, p4);
|
|
5815
|
+
if (d1 * d2 < 0 && d3 * d4 < 0) {
|
|
5816
|
+
return true;
|
|
5817
|
+
}
|
|
5818
|
+
return false;
|
|
5819
|
+
}
|
|
5820
|
+
function chordsIntersect(newChord, existingChord, perimeter, newPort1, newPort2, existingPort1, existingPort2) {
|
|
5821
|
+
if (chordsCross(newChord, existingChord, perimeter)) {
|
|
5822
|
+
return true;
|
|
5823
|
+
}
|
|
5824
|
+
return lineSegmentsIntersect(
|
|
5825
|
+
newPort1.d,
|
|
5826
|
+
newPort2.d,
|
|
5827
|
+
existingPort1.d,
|
|
5828
|
+
existingPort2.d
|
|
5829
|
+
);
|
|
5830
|
+
}
|
|
5781
5831
|
function computeDifferentNetCrossingsForPolygon(region, port1, port2) {
|
|
5782
5832
|
const polygon2 = region.d.polygon;
|
|
5783
5833
|
if (!polygon2 || polygon2.length < 3) {
|
|
@@ -5790,16 +5840,20 @@ function computeDifferentNetCrossingsForPolygon(region, port1, port2) {
|
|
|
5790
5840
|
let crossings = 0;
|
|
5791
5841
|
const assignments = region.assignments ?? [];
|
|
5792
5842
|
for (const assignment of assignments) {
|
|
5793
|
-
const
|
|
5794
|
-
|
|
5795
|
-
|
|
5796
|
-
);
|
|
5797
|
-
const existingT2 = getPortPerimeterTInRegion(
|
|
5798
|
-
assignment.regionPort2,
|
|
5799
|
-
region
|
|
5800
|
-
);
|
|
5843
|
+
const existingPort1 = assignment.regionPort1;
|
|
5844
|
+
const existingPort2 = assignment.regionPort2;
|
|
5845
|
+
const existingT1 = getPortPerimeterTInRegion(existingPort1, region);
|
|
5846
|
+
const existingT2 = getPortPerimeterTInRegion(existingPort2, region);
|
|
5801
5847
|
const existingChord = [existingT1, existingT2];
|
|
5802
|
-
if (
|
|
5848
|
+
if (chordsIntersect(
|
|
5849
|
+
newChord,
|
|
5850
|
+
existingChord,
|
|
5851
|
+
perimeter,
|
|
5852
|
+
port1,
|
|
5853
|
+
port2,
|
|
5854
|
+
existingPort1,
|
|
5855
|
+
existingPort2
|
|
5856
|
+
)) {
|
|
5803
5857
|
crossings++;
|
|
5804
5858
|
}
|
|
5805
5859
|
}
|
|
@@ -5817,16 +5871,20 @@ function computeCrossingAssignmentsForPolygon(region, port1, port2) {
|
|
|
5817
5871
|
const crossingAssignments = [];
|
|
5818
5872
|
const assignments = region.assignments ?? [];
|
|
5819
5873
|
for (const assignment of assignments) {
|
|
5820
|
-
const
|
|
5821
|
-
|
|
5822
|
-
|
|
5823
|
-
);
|
|
5824
|
-
const existingT2 = getPortPerimeterTInRegion(
|
|
5825
|
-
assignment.regionPort2,
|
|
5826
|
-
region
|
|
5827
|
-
);
|
|
5874
|
+
const existingPort1 = assignment.regionPort1;
|
|
5875
|
+
const existingPort2 = assignment.regionPort2;
|
|
5876
|
+
const existingT1 = getPortPerimeterTInRegion(existingPort1, region);
|
|
5877
|
+
const existingT2 = getPortPerimeterTInRegion(existingPort2, region);
|
|
5828
5878
|
const existingChord = [existingT1, existingT2];
|
|
5829
|
-
if (
|
|
5879
|
+
if (chordsIntersect(
|
|
5880
|
+
newChord,
|
|
5881
|
+
existingChord,
|
|
5882
|
+
perimeter,
|
|
5883
|
+
port1,
|
|
5884
|
+
port2,
|
|
5885
|
+
existingPort1,
|
|
5886
|
+
existingPort2
|
|
5887
|
+
)) {
|
|
5830
5888
|
crossingAssignments.push(assignment);
|
|
5831
5889
|
}
|
|
5832
5890
|
}
|
|
@@ -15697,10 +15755,7 @@ function findSharedEdges(polygon1, polygon2, tolerance = 0.01) {
|
|
|
15697
15755
|
x: a1.x + overlap.to * dx,
|
|
15698
15756
|
y: a1.y + overlap.to * dy
|
|
15699
15757
|
};
|
|
15700
|
-
|
|
15701
|
-
if (edgeLen > tolerance) {
|
|
15702
|
-
sharedEdges.push({ from, to });
|
|
15703
|
-
}
|
|
15758
|
+
sharedEdges.push({ from, to });
|
|
15704
15759
|
}
|
|
15705
15760
|
}
|
|
15706
15761
|
return sharedEdges;
|
|
@@ -15768,35 +15823,6 @@ function centroid(points) {
|
|
|
15768
15823
|
}
|
|
15769
15824
|
return { x: cx / points.length, y: cy / points.length };
|
|
15770
15825
|
}
|
|
15771
|
-
function classifySideFromBounds(point2, bounds) {
|
|
15772
|
-
const distances = {
|
|
15773
|
-
left: Math.abs(point2.x - bounds.minX),
|
|
15774
|
-
right: Math.abs(point2.x - bounds.maxX),
|
|
15775
|
-
bottom: Math.abs(point2.y - bounds.minY),
|
|
15776
|
-
top: Math.abs(point2.y - bounds.maxY)
|
|
15777
|
-
};
|
|
15778
|
-
let bestSide = "left";
|
|
15779
|
-
let bestDistance = distances.left;
|
|
15780
|
-
for (const side of ["right", "bottom", "top"]) {
|
|
15781
|
-
if (distances[side] < bestDistance) {
|
|
15782
|
-
bestSide = side;
|
|
15783
|
-
bestDistance = distances[side];
|
|
15784
|
-
}
|
|
15785
|
-
}
|
|
15786
|
-
return bestSide;
|
|
15787
|
-
}
|
|
15788
|
-
function toCandidateKey(regionId, point2) {
|
|
15789
|
-
return `${regionId}:${point2.x.toFixed(6)},${point2.y.toFixed(6)}`;
|
|
15790
|
-
}
|
|
15791
|
-
function compareCandidateQuality(a, b) {
|
|
15792
|
-
if (Math.abs(a.primaryDistance - b.primaryDistance) > 1e-6) {
|
|
15793
|
-
return b.primaryDistance - a.primaryDistance;
|
|
15794
|
-
}
|
|
15795
|
-
if (Math.abs(a.orthDistance - b.orthDistance) > 1e-6) {
|
|
15796
|
-
return a.orthDistance - b.orthDistance;
|
|
15797
|
-
}
|
|
15798
|
-
return a.key < b.key ? -1 : a.key > b.key ? 1 : 0;
|
|
15799
|
-
}
|
|
15800
15826
|
function createRegionFromPolygon(regionId, polygon2, opts) {
|
|
15801
15827
|
const bounds = boundsFromPolygon(polygon2);
|
|
15802
15828
|
return {
|
|
@@ -15879,6 +15905,124 @@ function translateRouteSegments(routeSegments, dx, dy, prefix) {
|
|
|
15879
15905
|
}))
|
|
15880
15906
|
}));
|
|
15881
15907
|
}
|
|
15908
|
+
function translatePolygon(polygon2, dx, dy) {
|
|
15909
|
+
return polygon2.map((p) => ({ x: p.x + dx, y: p.y + dy }));
|
|
15910
|
+
}
|
|
15911
|
+
function rectPolygonFromBounds(b) {
|
|
15912
|
+
return [
|
|
15913
|
+
{ x: b.minX, y: b.minY },
|
|
15914
|
+
{ x: b.maxX, y: b.minY },
|
|
15915
|
+
{ x: b.maxX, y: b.maxY },
|
|
15916
|
+
{ x: b.minX, y: b.maxY }
|
|
15917
|
+
];
|
|
15918
|
+
}
|
|
15919
|
+
function extendViaRegionToTileEdge(polygon2, tileBounds, threshold = 0.1) {
|
|
15920
|
+
if (polygon2.length === 0) return polygon2;
|
|
15921
|
+
const polyBounds = boundsFromPolygon(polygon2);
|
|
15922
|
+
const distToLeft = polyBounds.minX - tileBounds.minX;
|
|
15923
|
+
const distToRight = tileBounds.maxX - polyBounds.maxX;
|
|
15924
|
+
const distToBottom = polyBounds.minY - tileBounds.minY;
|
|
15925
|
+
const distToTop = tileBounds.maxY - polyBounds.maxY;
|
|
15926
|
+
const extendLeft = distToLeft > 0 && distToLeft < threshold;
|
|
15927
|
+
const extendRight = distToRight > 0 && distToRight < threshold;
|
|
15928
|
+
const extendBottom = distToBottom > 0 && distToBottom < threshold;
|
|
15929
|
+
const extendTop = distToTop > 0 && distToTop < threshold;
|
|
15930
|
+
if (!extendLeft && !extendRight && !extendBottom && !extendTop) {
|
|
15931
|
+
return polygon2;
|
|
15932
|
+
}
|
|
15933
|
+
const result = polygon2.map((p) => {
|
|
15934
|
+
let x = p.x;
|
|
15935
|
+
let y = p.y;
|
|
15936
|
+
if (extendLeft && Math.abs(p.x - polyBounds.minX) < 1e-3) {
|
|
15937
|
+
x = tileBounds.minX;
|
|
15938
|
+
}
|
|
15939
|
+
if (extendRight && Math.abs(p.x - polyBounds.maxX) < 1e-3) {
|
|
15940
|
+
x = tileBounds.maxX;
|
|
15941
|
+
}
|
|
15942
|
+
if (extendBottom && Math.abs(p.y - polyBounds.minY) < 1e-3) {
|
|
15943
|
+
y = tileBounds.minY;
|
|
15944
|
+
}
|
|
15945
|
+
if (extendTop && Math.abs(p.y - polyBounds.maxY) < 1e-3) {
|
|
15946
|
+
y = tileBounds.maxY;
|
|
15947
|
+
}
|
|
15948
|
+
return { x, y };
|
|
15949
|
+
});
|
|
15950
|
+
return deduplicateConsecutivePoints(result);
|
|
15951
|
+
}
|
|
15952
|
+
function pointInPolygon(point2, polygon2) {
|
|
15953
|
+
let inside2 = false;
|
|
15954
|
+
const n = polygon2.length;
|
|
15955
|
+
for (let i = 0, j = n - 1; i < n; j = i++) {
|
|
15956
|
+
const xi = polygon2[i].x;
|
|
15957
|
+
const yi = polygon2[i].y;
|
|
15958
|
+
const xj = polygon2[j].x;
|
|
15959
|
+
const yj = polygon2[j].y;
|
|
15960
|
+
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;
|
|
15961
|
+
if (onEdge) return true;
|
|
15962
|
+
if (yi > point2.y !== yj > point2.y) {
|
|
15963
|
+
const intersectX = (xj - xi) * (point2.y - yi) / (yj - yi) + xi;
|
|
15964
|
+
if (point2.x < intersectX) {
|
|
15965
|
+
inside2 = !inside2;
|
|
15966
|
+
}
|
|
15967
|
+
}
|
|
15968
|
+
}
|
|
15969
|
+
return inside2;
|
|
15970
|
+
}
|
|
15971
|
+
function findRegionContainingPoint(point2, regions) {
|
|
15972
|
+
for (const region of regions) {
|
|
15973
|
+
if (region.d.polygon && pointInPolygon(point2, region.d.polygon)) {
|
|
15974
|
+
return region;
|
|
15975
|
+
}
|
|
15976
|
+
}
|
|
15977
|
+
return null;
|
|
15978
|
+
}
|
|
15979
|
+
function computeUnitTileTemplate(viaTile, tileWidth, tileHeight, clearance, concavityTolerance) {
|
|
15980
|
+
const halfWidth = tileWidth / 2;
|
|
15981
|
+
const halfHeight = tileHeight / 2;
|
|
15982
|
+
const tileBounds = {
|
|
15983
|
+
minX: -halfWidth,
|
|
15984
|
+
maxX: halfWidth,
|
|
15985
|
+
minY: -halfHeight,
|
|
15986
|
+
maxY: halfHeight
|
|
15987
|
+
};
|
|
15988
|
+
const viaRegions = [];
|
|
15989
|
+
for (const [netName, vias] of Object.entries(viaTile.viasByNet)) {
|
|
15990
|
+
if (vias.length === 0) continue;
|
|
15991
|
+
const polygon2 = generateViaRegionPolygon(vias);
|
|
15992
|
+
if (polygon2.length === 0) continue;
|
|
15993
|
+
viaRegions.push({
|
|
15994
|
+
netName,
|
|
15995
|
+
polygon: polygon2,
|
|
15996
|
+
bounds: boundsFromPolygon(polygon2),
|
|
15997
|
+
center: centroid(polygon2)
|
|
15998
|
+
});
|
|
15999
|
+
}
|
|
16000
|
+
const obstaclePolygons = viaRegions.map((r) => ({
|
|
16001
|
+
points: extendViaRegionToTileEdge(r.polygon, tileBounds)
|
|
16002
|
+
}));
|
|
16003
|
+
const solver = new ConvexRegionsSolver({
|
|
16004
|
+
bounds: tileBounds,
|
|
16005
|
+
polygons: obstaclePolygons,
|
|
16006
|
+
clearance,
|
|
16007
|
+
concavityTolerance
|
|
16008
|
+
});
|
|
16009
|
+
solver.solve();
|
|
16010
|
+
const solverOutput = solver.getOutput();
|
|
16011
|
+
if (!solverOutput) {
|
|
16012
|
+
throw new Error("ConvexRegionsSolver failed to compute unit tile regions");
|
|
16013
|
+
}
|
|
16014
|
+
const convexRegions = solverOutput.regions.map((polygon2) => ({
|
|
16015
|
+
polygon: polygon2,
|
|
16016
|
+
bounds: boundsFromPolygon(polygon2),
|
|
16017
|
+
center: centroid(polygon2)
|
|
16018
|
+
}));
|
|
16019
|
+
return {
|
|
16020
|
+
viaRegions,
|
|
16021
|
+
convexRegions,
|
|
16022
|
+
tileWidth,
|
|
16023
|
+
tileHeight
|
|
16024
|
+
};
|
|
16025
|
+
}
|
|
15882
16026
|
function generateConvexViaTopologyRegions(opts) {
|
|
15883
16027
|
const tileWidth = opts.tileWidth ?? opts.tileSize ?? opts.viaTile.tileWidth;
|
|
15884
16028
|
const tileHeight = opts.tileHeight ?? opts.tileSize ?? opts.viaTile.tileHeight;
|
|
@@ -15900,18 +16044,79 @@ function generateConvexViaTopologyRegions(opts) {
|
|
|
15900
16044
|
const allPorts = [];
|
|
15901
16045
|
const viaTile = { viasByNet: {}, routeSegments: [] };
|
|
15902
16046
|
const viaRegions = [];
|
|
16047
|
+
const convexRegions = [];
|
|
15903
16048
|
const gridWidth = cols * tileWidth;
|
|
15904
16049
|
const gridHeight = rows * tileHeight;
|
|
15905
16050
|
const gridMinX = bounds.minX + (width - gridWidth) / 2;
|
|
15906
16051
|
const gridMinY = bounds.minY + (height - gridHeight) / 2;
|
|
16052
|
+
const gridMaxX = gridMinX + gridWidth;
|
|
16053
|
+
const gridMaxY = gridMinY + gridHeight;
|
|
15907
16054
|
const halfWidth = tileWidth / 2;
|
|
15908
16055
|
const halfHeight = tileHeight / 2;
|
|
16056
|
+
let portIdCounter = 0;
|
|
16057
|
+
const usedPortPositions = /* @__PURE__ */ new Set();
|
|
16058
|
+
const getPortPosKey = (x, y) => `${x.toFixed(4)},${y.toFixed(4)}`;
|
|
16059
|
+
const createPort = (portId, region1, region2, pos) => {
|
|
16060
|
+
const posKey = getPortPosKey(pos.x, pos.y);
|
|
16061
|
+
if (usedPortPositions.has(posKey)) {
|
|
16062
|
+
return null;
|
|
16063
|
+
}
|
|
16064
|
+
usedPortPositions.add(posKey);
|
|
16065
|
+
const port = {
|
|
16066
|
+
portId,
|
|
16067
|
+
region1,
|
|
16068
|
+
region2,
|
|
16069
|
+
d: { x: pos.x, y: pos.y }
|
|
16070
|
+
};
|
|
16071
|
+
region1.ports.push(port);
|
|
16072
|
+
region2.ports.push(port);
|
|
16073
|
+
allPorts.push(port);
|
|
16074
|
+
return port;
|
|
16075
|
+
};
|
|
16076
|
+
let unitTileTemplate = null;
|
|
15909
16077
|
if (rows > 0 && cols > 0) {
|
|
16078
|
+
unitTileTemplate = computeUnitTileTemplate(
|
|
16079
|
+
inputViaTile,
|
|
16080
|
+
tileWidth,
|
|
16081
|
+
tileHeight,
|
|
16082
|
+
clearance,
|
|
16083
|
+
concavityTolerance
|
|
16084
|
+
);
|
|
16085
|
+
}
|
|
16086
|
+
if (rows > 0 && cols > 0 && unitTileTemplate) {
|
|
15910
16087
|
for (let row = 0; row < rows; row++) {
|
|
15911
16088
|
for (let col = 0; col < cols; col++) {
|
|
15912
16089
|
const tileCenterX = gridMinX + col * tileWidth + halfWidth;
|
|
15913
16090
|
const tileCenterY = gridMinY + row * tileHeight + halfHeight;
|
|
15914
16091
|
const prefix = `t${row}_${col}`;
|
|
16092
|
+
for (const templateViaRegion of unitTileTemplate.viaRegions) {
|
|
16093
|
+
const translatedPolygon = translatePolygon(
|
|
16094
|
+
templateViaRegion.polygon,
|
|
16095
|
+
tileCenterX,
|
|
16096
|
+
tileCenterY
|
|
16097
|
+
);
|
|
16098
|
+
const viaRegion = createRegionFromPolygon(
|
|
16099
|
+
`${prefix}:v:${templateViaRegion.netName}`,
|
|
16100
|
+
translatedPolygon,
|
|
16101
|
+
{ isViaRegion: true }
|
|
16102
|
+
);
|
|
16103
|
+
viaRegions.push(viaRegion);
|
|
16104
|
+
allRegions.push(viaRegion);
|
|
16105
|
+
}
|
|
16106
|
+
for (let i = 0; i < unitTileTemplate.convexRegions.length; i++) {
|
|
16107
|
+
const templateConvexRegion = unitTileTemplate.convexRegions[i];
|
|
16108
|
+
const translatedPolygon = translatePolygon(
|
|
16109
|
+
templateConvexRegion.polygon,
|
|
16110
|
+
tileCenterX,
|
|
16111
|
+
tileCenterY
|
|
16112
|
+
);
|
|
16113
|
+
const convexRegion = createRegionFromPolygon(
|
|
16114
|
+
`${prefix}:convex:${i}`,
|
|
16115
|
+
translatedPolygon
|
|
16116
|
+
);
|
|
16117
|
+
convexRegions.push(convexRegion);
|
|
16118
|
+
allRegions.push(convexRegion);
|
|
16119
|
+
}
|
|
15915
16120
|
for (const [netName, vias] of Object.entries(viasByNet)) {
|
|
15916
16121
|
if (vias.length === 0) continue;
|
|
15917
16122
|
const translatedVias = translateVias(
|
|
@@ -15924,15 +16129,6 @@ function generateConvexViaTopologyRegions(opts) {
|
|
|
15924
16129
|
viaTile.viasByNet[netName] = [];
|
|
15925
16130
|
}
|
|
15926
16131
|
viaTile.viasByNet[netName].push(...translatedVias);
|
|
15927
|
-
const polygon2 = generateViaRegionPolygon(translatedVias);
|
|
15928
|
-
if (polygon2.length === 0) continue;
|
|
15929
|
-
const viaRegion = createRegionFromPolygon(
|
|
15930
|
-
`${prefix}:v:${netName}`,
|
|
15931
|
-
polygon2,
|
|
15932
|
-
{ isViaRegion: true }
|
|
15933
|
-
);
|
|
15934
|
-
viaRegions.push(viaRegion);
|
|
15935
|
-
allRegions.push(viaRegion);
|
|
15936
16132
|
}
|
|
15937
16133
|
viaTile.routeSegments.push(
|
|
15938
16134
|
...translateRouteSegments(
|
|
@@ -15945,55 +16141,306 @@ function generateConvexViaTopologyRegions(opts) {
|
|
|
15945
16141
|
}
|
|
15946
16142
|
}
|
|
15947
16143
|
}
|
|
15948
|
-
const
|
|
15949
|
-
|
|
15950
|
-
|
|
15951
|
-
const
|
|
15952
|
-
|
|
15953
|
-
|
|
15954
|
-
|
|
15955
|
-
|
|
15956
|
-
|
|
15957
|
-
const
|
|
15958
|
-
|
|
15959
|
-
const
|
|
15960
|
-
|
|
15961
|
-
|
|
16144
|
+
const fillerRegions = [];
|
|
16145
|
+
const topMargin = bounds.maxY - gridMaxY;
|
|
16146
|
+
const bottomMargin = gridMinY - bounds.minY;
|
|
16147
|
+
const leftMargin = gridMinX - bounds.minX;
|
|
16148
|
+
const rightMargin = bounds.maxX - gridMaxX;
|
|
16149
|
+
const verticalMargin = Math.max(topMargin, bottomMargin);
|
|
16150
|
+
const horizontalMargin = Math.max(leftMargin, rightMargin);
|
|
16151
|
+
const topBottomGetCorners = verticalMargin >= horizontalMargin;
|
|
16152
|
+
const topMinX = topBottomGetCorners ? bounds.minX : gridMinX;
|
|
16153
|
+
const topMaxX = topBottomGetCorners ? bounds.maxX : gridMaxX;
|
|
16154
|
+
const bottomMinX = topBottomGetCorners ? bounds.minX : gridMinX;
|
|
16155
|
+
const bottomMaxX = topBottomGetCorners ? bounds.maxX : gridMaxX;
|
|
16156
|
+
const leftMinY = topBottomGetCorners ? gridMinY : bounds.minY;
|
|
16157
|
+
const leftMaxY = topBottomGetCorners ? gridMaxY : bounds.maxY;
|
|
16158
|
+
const rightMinY = topBottomGetCorners ? gridMinY : bounds.minY;
|
|
16159
|
+
const rightMaxY = topBottomGetCorners ? gridMaxY : bounds.maxY;
|
|
16160
|
+
if (topMargin > 1e-3) {
|
|
16161
|
+
const topWidth = topMaxX - topMinX;
|
|
16162
|
+
const targetStripWidth = Math.max(topMargin, portPitch);
|
|
16163
|
+
const numTopStrips = Math.max(1, Math.floor(topWidth / targetStripWidth));
|
|
16164
|
+
const stripWidth = topWidth / numTopStrips;
|
|
16165
|
+
for (let i = 0; i < numTopStrips; i++) {
|
|
16166
|
+
const fillerBounds = {
|
|
16167
|
+
minX: topMinX + i * stripWidth,
|
|
16168
|
+
maxX: topMinX + (i + 1) * stripWidth,
|
|
16169
|
+
minY: gridMaxY,
|
|
16170
|
+
maxY: bounds.maxY
|
|
16171
|
+
};
|
|
16172
|
+
const regionId = `filler:top:${i}`;
|
|
16173
|
+
const filler = createRegionFromPolygon(
|
|
16174
|
+
regionId,
|
|
16175
|
+
rectPolygonFromBounds(fillerBounds)
|
|
16176
|
+
);
|
|
16177
|
+
fillerRegions.push(filler);
|
|
16178
|
+
allRegions.push(filler);
|
|
16179
|
+
}
|
|
15962
16180
|
}
|
|
15963
|
-
|
|
15964
|
-
|
|
15965
|
-
|
|
15966
|
-
|
|
15967
|
-
|
|
15968
|
-
|
|
15969
|
-
|
|
15970
|
-
|
|
15971
|
-
|
|
16181
|
+
if (bottomMargin > 1e-3) {
|
|
16182
|
+
const bottomWidth = bottomMaxX - bottomMinX;
|
|
16183
|
+
const targetStripWidth = Math.max(bottomMargin, portPitch);
|
|
16184
|
+
const numBottomStrips = Math.max(
|
|
16185
|
+
1,
|
|
16186
|
+
Math.floor(bottomWidth / targetStripWidth)
|
|
16187
|
+
);
|
|
16188
|
+
const stripWidth = bottomWidth / numBottomStrips;
|
|
16189
|
+
for (let i = 0; i < numBottomStrips; i++) {
|
|
16190
|
+
const fillerBounds = {
|
|
16191
|
+
minX: bottomMinX + i * stripWidth,
|
|
16192
|
+
maxX: bottomMinX + (i + 1) * stripWidth,
|
|
16193
|
+
minY: bounds.minY,
|
|
16194
|
+
maxY: gridMinY
|
|
16195
|
+
};
|
|
16196
|
+
const regionId = `filler:bottom:${i}`;
|
|
16197
|
+
const filler = createRegionFromPolygon(
|
|
16198
|
+
regionId,
|
|
16199
|
+
rectPolygonFromBounds(fillerBounds)
|
|
16200
|
+
);
|
|
16201
|
+
fillerRegions.push(filler);
|
|
16202
|
+
allRegions.push(filler);
|
|
16203
|
+
}
|
|
16204
|
+
}
|
|
16205
|
+
if (leftMargin > 1e-3) {
|
|
16206
|
+
const leftHeight = leftMaxY - leftMinY;
|
|
16207
|
+
const targetStripHeight = Math.max(leftMargin, portPitch);
|
|
16208
|
+
const numLeftStrips = Math.max(
|
|
16209
|
+
1,
|
|
16210
|
+
Math.floor(leftHeight / targetStripHeight)
|
|
16211
|
+
);
|
|
16212
|
+
const stripHeight = leftHeight / numLeftStrips;
|
|
16213
|
+
for (let i = 0; i < numLeftStrips; i++) {
|
|
16214
|
+
const fillerBounds = {
|
|
16215
|
+
minX: bounds.minX,
|
|
16216
|
+
maxX: gridMinX,
|
|
16217
|
+
minY: leftMinY + i * stripHeight,
|
|
16218
|
+
maxY: leftMinY + (i + 1) * stripHeight
|
|
16219
|
+
};
|
|
16220
|
+
const regionId = `filler:left:${i}`;
|
|
16221
|
+
const filler = createRegionFromPolygon(
|
|
16222
|
+
regionId,
|
|
16223
|
+
rectPolygonFromBounds(fillerBounds)
|
|
16224
|
+
);
|
|
16225
|
+
fillerRegions.push(filler);
|
|
16226
|
+
allRegions.push(filler);
|
|
16227
|
+
}
|
|
16228
|
+
}
|
|
16229
|
+
if (rightMargin > 1e-3) {
|
|
16230
|
+
const rightHeight = rightMaxY - rightMinY;
|
|
16231
|
+
const targetStripHeight = Math.max(rightMargin, portPitch);
|
|
16232
|
+
const numRightStrips = Math.max(
|
|
16233
|
+
1,
|
|
16234
|
+
Math.floor(rightHeight / targetStripHeight)
|
|
16235
|
+
);
|
|
16236
|
+
const stripHeight = rightHeight / numRightStrips;
|
|
16237
|
+
for (let i = 0; i < numRightStrips; i++) {
|
|
16238
|
+
const fillerBounds = {
|
|
16239
|
+
minX: gridMaxX,
|
|
16240
|
+
maxX: bounds.maxX,
|
|
16241
|
+
minY: rightMinY + i * stripHeight,
|
|
16242
|
+
maxY: rightMinY + (i + 1) * stripHeight
|
|
16243
|
+
};
|
|
16244
|
+
const regionId = `filler:right:${i}`;
|
|
16245
|
+
const filler = createRegionFromPolygon(
|
|
16246
|
+
regionId,
|
|
16247
|
+
rectPolygonFromBounds(fillerBounds)
|
|
16248
|
+
);
|
|
16249
|
+
fillerRegions.push(filler);
|
|
16250
|
+
allRegions.push(filler);
|
|
16251
|
+
}
|
|
16252
|
+
}
|
|
16253
|
+
if (unitTileTemplate && rows > 0 && cols > 0) {
|
|
16254
|
+
const regionsPerTile = unitTileTemplate.convexRegions.length;
|
|
16255
|
+
for (let row = 0; row < rows; row++) {
|
|
16256
|
+
for (let col = 0; col < cols; col++) {
|
|
16257
|
+
const tileIndex = row * cols + col;
|
|
16258
|
+
const tileStartIdx = tileIndex * regionsPerTile;
|
|
16259
|
+
for (let i = 0; i < regionsPerTile; i++) {
|
|
16260
|
+
for (let j = i + 1; j < regionsPerTile; j++) {
|
|
16261
|
+
const region1 = convexRegions[tileStartIdx + i];
|
|
16262
|
+
const region2 = convexRegions[tileStartIdx + j];
|
|
16263
|
+
const sharedEdges = findSharedEdges(
|
|
16264
|
+
region1.d.polygon,
|
|
16265
|
+
region2.d.polygon,
|
|
16266
|
+
clearance * 2
|
|
16267
|
+
);
|
|
16268
|
+
for (const edge of sharedEdges) {
|
|
16269
|
+
const portPositions = createPortsAlongEdge(edge, portPitch);
|
|
16270
|
+
for (const pos of portPositions) {
|
|
16271
|
+
createPort(
|
|
16272
|
+
`t${row}_${col}:convex:${i}-${j}:${portIdCounter++}`,
|
|
16273
|
+
region1,
|
|
16274
|
+
region2,
|
|
16275
|
+
pos
|
|
16276
|
+
);
|
|
16277
|
+
}
|
|
16278
|
+
}
|
|
16279
|
+
}
|
|
16280
|
+
}
|
|
16281
|
+
}
|
|
16282
|
+
}
|
|
16283
|
+
}
|
|
16284
|
+
if (unitTileTemplate && rows > 0 && cols > 0) {
|
|
16285
|
+
const convexPerTile = unitTileTemplate.convexRegions.length;
|
|
16286
|
+
const viasPerTile = unitTileTemplate.viaRegions.length;
|
|
16287
|
+
const numVerticalPorts = Math.floor(tileHeight / portPitch);
|
|
16288
|
+
const verticalPortYOffsets = [];
|
|
16289
|
+
for (let i = 0; i < numVerticalPorts; i++) {
|
|
16290
|
+
verticalPortYOffsets.push(-halfHeight + (i + 0.5) * portPitch);
|
|
16291
|
+
}
|
|
16292
|
+
const numHorizontalPorts = Math.floor(tileWidth / portPitch);
|
|
16293
|
+
const horizontalPortXOffsets = [];
|
|
16294
|
+
for (let i = 0; i < numHorizontalPorts; i++) {
|
|
16295
|
+
horizontalPortXOffsets.push(-halfWidth + (i + 0.5) * portPitch);
|
|
16296
|
+
}
|
|
16297
|
+
for (let row = 0; row < rows; row++) {
|
|
16298
|
+
for (let col = 0; col < cols; col++) {
|
|
16299
|
+
const tileIndex = row * cols + col;
|
|
16300
|
+
const convexStartIdx = tileIndex * convexPerTile;
|
|
16301
|
+
const viaStartIdx = tileIndex * viasPerTile;
|
|
16302
|
+
const tileCenterX = gridMinX + col * tileWidth + halfWidth;
|
|
16303
|
+
const tileCenterY = gridMinY + row * tileHeight + halfHeight;
|
|
16304
|
+
const tileConvexRegions = convexRegions.slice(
|
|
16305
|
+
convexStartIdx,
|
|
16306
|
+
convexStartIdx + convexPerTile
|
|
16307
|
+
);
|
|
16308
|
+
const tileViaRegions = viaRegions.slice(
|
|
16309
|
+
viaStartIdx,
|
|
16310
|
+
viaStartIdx + viasPerTile
|
|
16311
|
+
);
|
|
16312
|
+
const tileAllRegions = [...tileConvexRegions, ...tileViaRegions];
|
|
16313
|
+
if (col + 1 < cols) {
|
|
16314
|
+
const rightTileIndex = row * cols + (col + 1);
|
|
16315
|
+
const rightConvexStartIdx = rightTileIndex * convexPerTile;
|
|
16316
|
+
const rightViaStartIdx = rightTileIndex * viasPerTile;
|
|
16317
|
+
const rightTileConvexRegions = convexRegions.slice(
|
|
16318
|
+
rightConvexStartIdx,
|
|
16319
|
+
rightConvexStartIdx + convexPerTile
|
|
16320
|
+
);
|
|
16321
|
+
const rightTileViaRegions = viaRegions.slice(
|
|
16322
|
+
rightViaStartIdx,
|
|
16323
|
+
rightViaStartIdx + viasPerTile
|
|
16324
|
+
);
|
|
16325
|
+
const rightTileAllRegions = [
|
|
16326
|
+
...rightTileConvexRegions,
|
|
16327
|
+
...rightTileViaRegions
|
|
16328
|
+
];
|
|
16329
|
+
const boundaryX = tileCenterX + halfWidth;
|
|
16330
|
+
for (const yOffset of verticalPortYOffsets) {
|
|
16331
|
+
const portY = tileCenterY + yOffset;
|
|
16332
|
+
const pointInCurrentTile = { x: boundaryX - 0.01, y: portY };
|
|
16333
|
+
const pointInRightTile = { x: boundaryX + 0.01, y: portY };
|
|
16334
|
+
const region1 = findRegionContainingPoint(
|
|
16335
|
+
pointInCurrentTile,
|
|
16336
|
+
tileAllRegions
|
|
16337
|
+
);
|
|
16338
|
+
const region2 = findRegionContainingPoint(
|
|
16339
|
+
pointInRightTile,
|
|
16340
|
+
rightTileAllRegions
|
|
16341
|
+
);
|
|
16342
|
+
if (region1 && region2) {
|
|
16343
|
+
createPort(
|
|
16344
|
+
`tile:${row}_${col}-${row}_${col + 1}:${portIdCounter++}`,
|
|
16345
|
+
region1,
|
|
16346
|
+
region2,
|
|
16347
|
+
{ x: boundaryX, y: portY }
|
|
16348
|
+
);
|
|
16349
|
+
}
|
|
16350
|
+
}
|
|
16351
|
+
}
|
|
16352
|
+
if (row + 1 < rows) {
|
|
16353
|
+
const topTileIndex = (row + 1) * cols + col;
|
|
16354
|
+
const topConvexStartIdx = topTileIndex * convexPerTile;
|
|
16355
|
+
const topViaStartIdx = topTileIndex * viasPerTile;
|
|
16356
|
+
const topTileConvexRegions = convexRegions.slice(
|
|
16357
|
+
topConvexStartIdx,
|
|
16358
|
+
topConvexStartIdx + convexPerTile
|
|
16359
|
+
);
|
|
16360
|
+
const topTileViaRegions = viaRegions.slice(
|
|
16361
|
+
topViaStartIdx,
|
|
16362
|
+
topViaStartIdx + viasPerTile
|
|
16363
|
+
);
|
|
16364
|
+
const topTileAllRegions = [
|
|
16365
|
+
...topTileConvexRegions,
|
|
16366
|
+
...topTileViaRegions
|
|
16367
|
+
];
|
|
16368
|
+
const boundaryY = tileCenterY + halfHeight;
|
|
16369
|
+
for (const xOffset of horizontalPortXOffsets) {
|
|
16370
|
+
const portX = tileCenterX + xOffset;
|
|
16371
|
+
const pointInCurrentTile = { x: portX, y: boundaryY - 0.01 };
|
|
16372
|
+
const pointInTopTile = { x: portX, y: boundaryY + 0.01 };
|
|
16373
|
+
const region1 = findRegionContainingPoint(
|
|
16374
|
+
pointInCurrentTile,
|
|
16375
|
+
tileAllRegions
|
|
16376
|
+
);
|
|
16377
|
+
const region2 = findRegionContainingPoint(
|
|
16378
|
+
pointInTopTile,
|
|
16379
|
+
topTileAllRegions
|
|
16380
|
+
);
|
|
16381
|
+
if (region1 && region2) {
|
|
16382
|
+
createPort(
|
|
16383
|
+
`tile:${row}_${col}-${row + 1}_${col}:${portIdCounter++}`,
|
|
16384
|
+
region1,
|
|
16385
|
+
region2,
|
|
16386
|
+
{ x: portX, y: boundaryY }
|
|
16387
|
+
);
|
|
16388
|
+
}
|
|
16389
|
+
}
|
|
16390
|
+
}
|
|
16391
|
+
}
|
|
16392
|
+
}
|
|
16393
|
+
}
|
|
16394
|
+
for (const fillerRegion of fillerRegions) {
|
|
16395
|
+
const tileRegions = [...convexRegions, ...viaRegions];
|
|
16396
|
+
for (const tileRegion of tileRegions) {
|
|
16397
|
+
const sharedEdges = findSharedEdges(
|
|
16398
|
+
tileRegion.d.polygon,
|
|
16399
|
+
fillerRegion.d.polygon,
|
|
16400
|
+
clearance * 2
|
|
16401
|
+
);
|
|
16402
|
+
for (const edge of sharedEdges) {
|
|
16403
|
+
const portPositions = createPortsAlongEdge(edge, portPitch);
|
|
16404
|
+
for (const pos of portPositions) {
|
|
16405
|
+
createPort(
|
|
16406
|
+
`filler:${tileRegion.regionId}-${fillerRegion.regionId}:${portIdCounter++}`,
|
|
16407
|
+
tileRegion,
|
|
16408
|
+
fillerRegion,
|
|
16409
|
+
pos
|
|
16410
|
+
);
|
|
16411
|
+
}
|
|
16412
|
+
}
|
|
16413
|
+
}
|
|
16414
|
+
}
|
|
16415
|
+
for (let i = 0; i < fillerRegions.length; i++) {
|
|
16416
|
+
for (let j = i + 1; j < fillerRegions.length; j++) {
|
|
16417
|
+
const region1 = fillerRegions[i];
|
|
16418
|
+
const region2 = fillerRegions[j];
|
|
15972
16419
|
const sharedEdges = findSharedEdges(
|
|
15973
16420
|
region1.d.polygon,
|
|
15974
16421
|
region2.d.polygon,
|
|
15975
|
-
|
|
15976
|
-
// tolerance slightly larger than clearance
|
|
16422
|
+
0.01
|
|
15977
16423
|
);
|
|
15978
16424
|
for (const edge of sharedEdges) {
|
|
16425
|
+
const edgeLength = Math.sqrt(
|
|
16426
|
+
(edge.to.x - edge.from.x) ** 2 + (edge.to.y - edge.from.y) ** 2
|
|
16427
|
+
);
|
|
16428
|
+
if (edgeLength < portPitch) {
|
|
16429
|
+
continue;
|
|
16430
|
+
}
|
|
15979
16431
|
const portPositions = createPortsAlongEdge(edge, portPitch);
|
|
15980
16432
|
for (const pos of portPositions) {
|
|
15981
|
-
|
|
15982
|
-
|
|
16433
|
+
createPort(
|
|
16434
|
+
`filler:${region1.regionId}-${region2.regionId}:${portIdCounter++}`,
|
|
15983
16435
|
region1,
|
|
15984
16436
|
region2,
|
|
15985
|
-
|
|
15986
|
-
|
|
15987
|
-
region1.ports.push(port);
|
|
15988
|
-
region2.ports.push(port);
|
|
15989
|
-
allPorts.push(port);
|
|
16437
|
+
pos
|
|
16438
|
+
);
|
|
15990
16439
|
}
|
|
15991
16440
|
}
|
|
15992
16441
|
}
|
|
15993
16442
|
}
|
|
15994
16443
|
for (const viaRegion of viaRegions) {
|
|
15995
|
-
const viaCenter = viaRegion.d.center;
|
|
15996
|
-
const candidates = [];
|
|
15997
16444
|
for (const convexRegion of convexRegions) {
|
|
15998
16445
|
const sharedEdges = findSharedEdges(
|
|
15999
16446
|
viaRegion.d.polygon,
|
|
@@ -16003,55 +16450,15 @@ function generateConvexViaTopologyRegions(opts) {
|
|
|
16003
16450
|
for (const edge of sharedEdges) {
|
|
16004
16451
|
const portPositions = createPortsAlongEdge(edge, portPitch);
|
|
16005
16452
|
for (const pos of portPositions) {
|
|
16006
|
-
|
|
16007
|
-
|
|
16008
|
-
|
|
16009
|
-
const primaryDistance = side === "left" || side === "right" ? Math.abs(dx) : Math.abs(dy);
|
|
16010
|
-
const orthDistance = side === "left" || side === "right" ? Math.abs(dy) : Math.abs(dx);
|
|
16011
|
-
candidates.push({
|
|
16453
|
+
createPort(
|
|
16454
|
+
`via-convex:${viaRegion.regionId}-${convexRegion.regionId}:${portIdCounter++}`,
|
|
16455
|
+
viaRegion,
|
|
16012
16456
|
convexRegion,
|
|
16013
|
-
|
|
16014
|
-
|
|
16015
|
-
primaryDistance,
|
|
16016
|
-
orthDistance,
|
|
16017
|
-
key: toCandidateKey(convexRegion.regionId, pos)
|
|
16018
|
-
});
|
|
16457
|
+
pos
|
|
16458
|
+
);
|
|
16019
16459
|
}
|
|
16020
16460
|
}
|
|
16021
16461
|
}
|
|
16022
|
-
if (candidates.length === 0) continue;
|
|
16023
|
-
const selectedCandidates = [];
|
|
16024
|
-
const selectedKeys = /* @__PURE__ */ new Set();
|
|
16025
|
-
const addCandidate = (candidate) => {
|
|
16026
|
-
if (!candidate) return;
|
|
16027
|
-
if (selectedKeys.has(candidate.key)) return;
|
|
16028
|
-
selectedCandidates.push(candidate);
|
|
16029
|
-
selectedKeys.add(candidate.key);
|
|
16030
|
-
};
|
|
16031
|
-
for (const side of ["top", "bottom", "left", "right"]) {
|
|
16032
|
-
const sideCandidate = [...candidates].filter((candidate) => candidate.side === side).sort(compareCandidateQuality)[0];
|
|
16033
|
-
addCandidate(sideCandidate);
|
|
16034
|
-
}
|
|
16035
|
-
if (selectedCandidates.length < 4) {
|
|
16036
|
-
for (const candidate of [...candidates].sort(compareCandidateQuality)) {
|
|
16037
|
-
addCandidate(candidate);
|
|
16038
|
-
if (selectedCandidates.length >= 4) break;
|
|
16039
|
-
}
|
|
16040
|
-
}
|
|
16041
|
-
for (const selectedCandidate of selectedCandidates.slice(0, 4)) {
|
|
16042
|
-
const port = {
|
|
16043
|
-
portId: `via-convex:${viaRegion.regionId}-${selectedCandidate.convexRegion.regionId}:${portIdCounter++}`,
|
|
16044
|
-
region1: viaRegion,
|
|
16045
|
-
region2: selectedCandidate.convexRegion,
|
|
16046
|
-
d: {
|
|
16047
|
-
x: selectedCandidate.position.x,
|
|
16048
|
-
y: selectedCandidate.position.y
|
|
16049
|
-
}
|
|
16050
|
-
};
|
|
16051
|
-
viaRegion.ports.push(port);
|
|
16052
|
-
selectedCandidate.convexRegion.ports.push(port);
|
|
16053
|
-
allPorts.push(port);
|
|
16054
|
-
}
|
|
16055
16462
|
}
|
|
16056
16463
|
return {
|
|
16057
16464
|
regions: allRegions,
|