@tscircuit/rectdiff 0.0.18 → 0.0.20
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 +4 -19
- package/dist/index.js +202 -131
- package/lib/fixtures/twoNodeExpansionFixture.ts +2 -9
- package/lib/solvers/RectDiffExpansionSolver/RectDiffExpansionSolver.ts +55 -108
- package/lib/solvers/RectDiffGridSolverPipeline/RectDiffGridSolverPipeline.ts +22 -7
- package/lib/solvers/RectDiffGridSolverPipeline/buildObstacleIndexes.ts +2 -1
- package/lib/solvers/RectDiffSeedingSolver/RectDiffSeedingSolver.ts +5 -16
- package/lib/types/capacity-mesh-types.ts +1 -0
- package/lib/utils/expandRectFromSeed.ts +89 -2
- package/lib/utils/isSelfRect.ts +15 -0
- package/lib/utils/rectToTree.ts +5 -1
- package/lib/utils/resizeSoftOverlaps.ts +8 -16
- package/lib/utils/searchStrip.ts +50 -0
- package/package.json +1 -1
- package/tests/__snapshots__/should-expand-node.snap.svg +2 -2
- package/tests/fixtures/makeSimpleRouteOutlineGraphics.ts +41 -0
- package/tests/incremental-solver.test.ts +1 -1
- package/tests/should-expand-node.test.ts +6 -3
- package/tests/solver/__snapshots__/rectDiffGridSolverPipeline.snap.svg +1 -1
- package/tests/solver/rectDiffGridSolverPipeline.test.ts +5 -1
package/dist/index.d.ts
CHANGED
|
@@ -113,6 +113,7 @@ type RTreeRect = XYRect & {
|
|
|
113
113
|
minY: number;
|
|
114
114
|
maxX: number;
|
|
115
115
|
maxY: number;
|
|
116
|
+
zLayers: number[];
|
|
116
117
|
};
|
|
117
118
|
|
|
118
119
|
interface SegmentWithAdjacentEmptySpace {
|
|
@@ -278,7 +279,7 @@ declare class RectDiffSeedingSolver extends BaseSolver {
|
|
|
278
279
|
visualize(): GraphicsObject;
|
|
279
280
|
}
|
|
280
281
|
|
|
281
|
-
type
|
|
282
|
+
type RectDiffExpansionSolverInput = {
|
|
282
283
|
srj: SimpleRouteJson;
|
|
283
284
|
layerNames: string[];
|
|
284
285
|
layerCount: number;
|
|
@@ -295,9 +296,6 @@ type RectDiffExpansionSolverSnapshot = {
|
|
|
295
296
|
edgeAnalysisDone: boolean;
|
|
296
297
|
totalSeedsThisGrid: number;
|
|
297
298
|
consumedSeedsThisGrid: number;
|
|
298
|
-
};
|
|
299
|
-
type RectDiffExpansionSolverInput = {
|
|
300
|
-
initialSnapshot: RectDiffExpansionSolverSnapshot;
|
|
301
299
|
obstacleIndexByLayer: Array<RBush<RTreeRect>>;
|
|
302
300
|
};
|
|
303
301
|
/**
|
|
@@ -308,21 +306,8 @@ type RectDiffExpansionSolverInput = {
|
|
|
308
306
|
*/
|
|
309
307
|
declare class RectDiffExpansionSolver extends BaseSolver {
|
|
310
308
|
private input;
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
private layerCount;
|
|
314
|
-
private bounds;
|
|
315
|
-
private options;
|
|
316
|
-
private boardVoidRects;
|
|
317
|
-
private gridIndex;
|
|
318
|
-
private candidates;
|
|
319
|
-
private placed;
|
|
320
|
-
private placedIndexByLayer;
|
|
321
|
-
private expansionIndex;
|
|
322
|
-
private edgeAnalysisDone;
|
|
323
|
-
private totalSeedsThisGrid;
|
|
324
|
-
private consumedSeedsThisGrid;
|
|
325
|
-
private _meshNodes;
|
|
309
|
+
placedIndexByLayer: Array<RBush<RTreeRect>>;
|
|
310
|
+
_meshNodes: CapacityMeshNode[];
|
|
326
311
|
constructor(input: RectDiffExpansionSolverInput);
|
|
327
312
|
_setup(): void;
|
|
328
313
|
_step(): void;
|
package/dist/index.js
CHANGED
|
@@ -897,6 +897,48 @@ function obstacleToXYRect(ob) {
|
|
|
897
897
|
return { x: ob.center.x - w / 2, y: ob.center.y - h / 2, width: w, height: h };
|
|
898
898
|
}
|
|
899
899
|
|
|
900
|
+
// lib/utils/isSelfRect.ts
|
|
901
|
+
var EPS5 = 1e-9;
|
|
902
|
+
var isSelfRect = (params) => Math.abs(params.rect.x + params.rect.width / 2 - params.startX) < EPS5 && Math.abs(params.rect.y + params.rect.height / 2 - params.startY) < EPS5 && Math.abs(params.rect.width - params.initialW) < EPS5 && Math.abs(params.rect.height - params.initialH) < EPS5;
|
|
903
|
+
|
|
904
|
+
// lib/utils/searchStrip.ts
|
|
905
|
+
var searchStripRight = ({
|
|
906
|
+
rect,
|
|
907
|
+
bounds
|
|
908
|
+
}) => ({
|
|
909
|
+
x: rect.x,
|
|
910
|
+
y: rect.y,
|
|
911
|
+
width: bounds.x + bounds.width - rect.x,
|
|
912
|
+
height: rect.height
|
|
913
|
+
});
|
|
914
|
+
var searchStripDown = ({
|
|
915
|
+
rect,
|
|
916
|
+
bounds
|
|
917
|
+
}) => ({
|
|
918
|
+
x: rect.x,
|
|
919
|
+
y: rect.y,
|
|
920
|
+
width: rect.width,
|
|
921
|
+
height: bounds.y + bounds.height - rect.y
|
|
922
|
+
});
|
|
923
|
+
var searchStripLeft = ({
|
|
924
|
+
rect,
|
|
925
|
+
bounds
|
|
926
|
+
}) => ({
|
|
927
|
+
x: bounds.x,
|
|
928
|
+
y: rect.y,
|
|
929
|
+
width: rect.x - bounds.x,
|
|
930
|
+
height: rect.height
|
|
931
|
+
});
|
|
932
|
+
var searchStripUp = ({
|
|
933
|
+
rect,
|
|
934
|
+
bounds
|
|
935
|
+
}) => ({
|
|
936
|
+
x: rect.x,
|
|
937
|
+
y: bounds.y,
|
|
938
|
+
width: rect.width,
|
|
939
|
+
height: rect.y - bounds.y
|
|
940
|
+
});
|
|
941
|
+
|
|
900
942
|
// lib/utils/expandRectFromSeed.ts
|
|
901
943
|
function maxExpandRight(params) {
|
|
902
944
|
const { r, bounds, blockers, maxAspect } = params;
|
|
@@ -982,13 +1024,36 @@ function maxExpandUp(params) {
|
|
|
982
1024
|
}
|
|
983
1025
|
return Math.max(0, e);
|
|
984
1026
|
}
|
|
1027
|
+
var toRect = (tree) => ({
|
|
1028
|
+
x: tree.minX,
|
|
1029
|
+
y: tree.minY,
|
|
1030
|
+
width: tree.maxX - tree.minX,
|
|
1031
|
+
height: tree.maxY - tree.minY
|
|
1032
|
+
});
|
|
1033
|
+
var addBlocker = (params) => {
|
|
1034
|
+
const { rect, seen, blockers } = params;
|
|
1035
|
+
const key = `${rect.x}|${rect.y}|${rect.width}|${rect.height}`;
|
|
1036
|
+
if (seen.has(key)) return;
|
|
1037
|
+
seen.add(key);
|
|
1038
|
+
blockers.push(rect);
|
|
1039
|
+
};
|
|
1040
|
+
var toQueryRect = (params) => {
|
|
1041
|
+
const { bounds, rect } = params;
|
|
1042
|
+
const minX = Math.max(bounds.x, rect.x);
|
|
1043
|
+
const minY = Math.max(bounds.y, rect.y);
|
|
1044
|
+
const maxX = Math.min(bounds.x + bounds.width, rect.x + rect.width);
|
|
1045
|
+
const maxY = Math.min(bounds.y + bounds.height, rect.y + rect.height);
|
|
1046
|
+
if (maxX <= minX + EPS4 || maxY <= minY + EPS4) return null;
|
|
1047
|
+
return { minX, minY, maxX, maxY };
|
|
1048
|
+
};
|
|
985
1049
|
function expandRectFromSeed(params) {
|
|
986
1050
|
const {
|
|
987
1051
|
startX,
|
|
988
1052
|
startY,
|
|
989
1053
|
gridSize,
|
|
990
1054
|
bounds,
|
|
991
|
-
|
|
1055
|
+
obsticalIndexByLayer,
|
|
1056
|
+
placedIndexByLayer,
|
|
992
1057
|
initialCellRatio,
|
|
993
1058
|
maxAspectRatio,
|
|
994
1059
|
minReq
|
|
@@ -996,6 +1061,37 @@ function expandRectFromSeed(params) {
|
|
|
996
1061
|
const minSide = Math.max(1e-9, gridSize * initialCellRatio);
|
|
997
1062
|
const initialW = Math.max(minSide, minReq.width);
|
|
998
1063
|
const initialH = Math.max(minSide, minReq.height);
|
|
1064
|
+
const blockers = [];
|
|
1065
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1066
|
+
const totalLayers = placedIndexByLayer.length;
|
|
1067
|
+
const collectBlockers = (searchRect) => {
|
|
1068
|
+
const query = toQueryRect({ bounds, rect: searchRect });
|
|
1069
|
+
if (!query) return;
|
|
1070
|
+
for (const z of params.zLayers) {
|
|
1071
|
+
const blockersIndex = obsticalIndexByLayer[z];
|
|
1072
|
+
if (blockersIndex) {
|
|
1073
|
+
for (const entry of blockersIndex.search(query))
|
|
1074
|
+
addBlocker({ rect: toRect(entry), seen, blockers });
|
|
1075
|
+
}
|
|
1076
|
+
const placedLayer = placedIndexByLayer[z];
|
|
1077
|
+
if (placedLayer) {
|
|
1078
|
+
for (const entry of placedLayer.search(query)) {
|
|
1079
|
+
const isFullStack = entry.zLayers.length >= totalLayers;
|
|
1080
|
+
if (!isFullStack) continue;
|
|
1081
|
+
const rect = toRect(entry);
|
|
1082
|
+
if (isSelfRect({
|
|
1083
|
+
rect,
|
|
1084
|
+
startX,
|
|
1085
|
+
startY,
|
|
1086
|
+
initialW,
|
|
1087
|
+
initialH
|
|
1088
|
+
}))
|
|
1089
|
+
continue;
|
|
1090
|
+
addBlocker({ rect, seen, blockers });
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
};
|
|
999
1095
|
const strategies = [
|
|
1000
1096
|
{ ox: 0, oy: 0 },
|
|
1001
1097
|
{ ox: -initialW, oy: 0 },
|
|
@@ -1012,6 +1108,7 @@ function expandRectFromSeed(params) {
|
|
|
1012
1108
|
width: initialW,
|
|
1013
1109
|
height: initialH
|
|
1014
1110
|
};
|
|
1111
|
+
collectBlockers(r);
|
|
1015
1112
|
if (lt(r.x, bounds.x) || lt(r.y, bounds.y) || gt(r.x + r.width, bounds.x + bounds.width) || gt(r.y + r.height, bounds.y + bounds.height)) {
|
|
1016
1113
|
continue;
|
|
1017
1114
|
}
|
|
@@ -1020,24 +1117,32 @@ function expandRectFromSeed(params) {
|
|
|
1020
1117
|
while (improved) {
|
|
1021
1118
|
improved = false;
|
|
1022
1119
|
const commonParams = { bounds, blockers, maxAspect: maxAspectRatio };
|
|
1120
|
+
collectBlockers(searchStripRight({ rect: r, bounds }));
|
|
1023
1121
|
const eR = maxExpandRight({ ...commonParams, r });
|
|
1024
1122
|
if (eR > 0) {
|
|
1025
1123
|
r = { ...r, width: r.width + eR };
|
|
1124
|
+
collectBlockers(r);
|
|
1026
1125
|
improved = true;
|
|
1027
1126
|
}
|
|
1127
|
+
collectBlockers(searchStripDown({ rect: r, bounds }));
|
|
1028
1128
|
const eD = maxExpandDown({ ...commonParams, r });
|
|
1029
1129
|
if (eD > 0) {
|
|
1030
1130
|
r = { ...r, height: r.height + eD };
|
|
1131
|
+
collectBlockers(r);
|
|
1031
1132
|
improved = true;
|
|
1032
1133
|
}
|
|
1134
|
+
collectBlockers(searchStripLeft({ rect: r, bounds }));
|
|
1033
1135
|
const eL = maxExpandLeft({ ...commonParams, r });
|
|
1034
1136
|
if (eL > 0) {
|
|
1035
1137
|
r = { x: r.x - eL, y: r.y, width: r.width + eL, height: r.height };
|
|
1138
|
+
collectBlockers(r);
|
|
1036
1139
|
improved = true;
|
|
1037
1140
|
}
|
|
1141
|
+
collectBlockers(searchStripUp({ rect: r, bounds }));
|
|
1038
1142
|
const eU = maxExpandUp({ ...commonParams, r });
|
|
1039
1143
|
if (eU > 0) {
|
|
1040
1144
|
r = { x: r.x, y: r.y - eU, width: r.width, height: r.height + eU };
|
|
1145
|
+
collectBlockers(r);
|
|
1041
1146
|
improved = true;
|
|
1042
1147
|
}
|
|
1043
1148
|
}
|
|
@@ -1471,6 +1576,16 @@ function allLayerNode(params) {
|
|
|
1471
1576
|
return out;
|
|
1472
1577
|
}
|
|
1473
1578
|
|
|
1579
|
+
// lib/utils/rectToTree.ts
|
|
1580
|
+
var rectToTree = (rect, opts) => ({
|
|
1581
|
+
...rect,
|
|
1582
|
+
minX: rect.x,
|
|
1583
|
+
minY: rect.y,
|
|
1584
|
+
maxX: rect.x + rect.width,
|
|
1585
|
+
maxY: rect.y + rect.height,
|
|
1586
|
+
zLayers: opts.zLayers
|
|
1587
|
+
});
|
|
1588
|
+
|
|
1474
1589
|
// lib/utils/resizeSoftOverlaps.ts
|
|
1475
1590
|
function resizeSoftOverlaps(params, newIndex) {
|
|
1476
1591
|
const newcomer = params.placed[newIndex];
|
|
@@ -1505,20 +1620,17 @@ function resizeSoftOverlaps(params, newIndex) {
|
|
|
1505
1620
|
}
|
|
1506
1621
|
}
|
|
1507
1622
|
}
|
|
1508
|
-
const rectToTree2 = (rect) => ({
|
|
1509
|
-
...rect,
|
|
1510
|
-
minX: rect.x,
|
|
1511
|
-
minY: rect.y,
|
|
1512
|
-
maxX: rect.x + rect.width,
|
|
1513
|
-
maxY: rect.y + rect.height
|
|
1514
|
-
});
|
|
1515
1623
|
const sameRect = (a, b) => a.minX === b.minX && a.minY === b.minY && a.maxX === b.maxX && a.maxY === b.maxY;
|
|
1516
1624
|
removeIdx.sort((a, b) => b - a).forEach((idx) => {
|
|
1517
1625
|
const rem = params.placed.splice(idx, 1)[0];
|
|
1518
1626
|
if (params.placedIndexByLayer) {
|
|
1519
1627
|
for (const z of rem.zLayers) {
|
|
1520
1628
|
const tree = params.placedIndexByLayer[z];
|
|
1521
|
-
if (tree)
|
|
1629
|
+
if (tree)
|
|
1630
|
+
tree.remove(
|
|
1631
|
+
rectToTree(rem.rect, { zLayers: rem.zLayers }),
|
|
1632
|
+
sameRect
|
|
1633
|
+
);
|
|
1522
1634
|
}
|
|
1523
1635
|
}
|
|
1524
1636
|
});
|
|
@@ -1528,13 +1640,7 @@ function resizeSoftOverlaps(params, newIndex) {
|
|
|
1528
1640
|
if (params.placedIndexByLayer) {
|
|
1529
1641
|
const idx = params.placedIndexByLayer[z];
|
|
1530
1642
|
if (idx) {
|
|
1531
|
-
idx.insert({
|
|
1532
|
-
...p.rect,
|
|
1533
|
-
minX: p.rect.x,
|
|
1534
|
-
minY: p.rect.y,
|
|
1535
|
-
maxX: p.rect.x + p.rect.width,
|
|
1536
|
-
maxY: p.rect.y + p.rect.height
|
|
1537
|
-
});
|
|
1643
|
+
idx.insert(rectToTree(p.rect, { zLayers: p.zLayers.slice() }));
|
|
1538
1644
|
}
|
|
1539
1645
|
}
|
|
1540
1646
|
}
|
|
@@ -1719,21 +1825,17 @@ var RectDiffSeedingSolver = class extends BaseSolver3 {
|
|
|
1719
1825
|
});
|
|
1720
1826
|
const ordered = preferMultiLayer ? attempts : attempts.reverse();
|
|
1721
1827
|
for (const attempt of ordered) {
|
|
1722
|
-
const hardBlockers = [];
|
|
1723
|
-
for (const z of attempt.layers) {
|
|
1724
|
-
const obstacleLayer = this.input.obstacleIndexByLayer[z];
|
|
1725
|
-
if (obstacleLayer) hardBlockers.push(...obstacleLayer.all());
|
|
1726
|
-
if (hardPlacedByLayer[z]) hardBlockers.push(...hardPlacedByLayer[z]);
|
|
1727
|
-
}
|
|
1728
1828
|
const rect = expandRectFromSeed({
|
|
1729
1829
|
startX: cand.x,
|
|
1730
1830
|
startY: cand.y,
|
|
1731
1831
|
gridSize: grid,
|
|
1732
1832
|
bounds: this.bounds,
|
|
1733
|
-
|
|
1833
|
+
obsticalIndexByLayer: this.input.obstacleIndexByLayer,
|
|
1834
|
+
placedIndexByLayer: this.placedIndexByLayer,
|
|
1734
1835
|
initialCellRatio,
|
|
1735
1836
|
maxAspectRatio,
|
|
1736
|
-
minReq: attempt.minReq
|
|
1837
|
+
minReq: attempt.minReq,
|
|
1838
|
+
zLayers: attempt.layers
|
|
1737
1839
|
});
|
|
1738
1840
|
if (!rect) continue;
|
|
1739
1841
|
const placed = { rect, zLayers: [...attempt.layers] };
|
|
@@ -1741,13 +1843,7 @@ var RectDiffSeedingSolver = class extends BaseSolver3 {
|
|
|
1741
1843
|
for (const z of attempt.layers) {
|
|
1742
1844
|
const idx = this.placedIndexByLayer[z];
|
|
1743
1845
|
if (idx) {
|
|
1744
|
-
idx.insert({
|
|
1745
|
-
...rect,
|
|
1746
|
-
minX: rect.x,
|
|
1747
|
-
minY: rect.y,
|
|
1748
|
-
maxX: rect.x + rect.width,
|
|
1749
|
-
maxY: rect.y + rect.height
|
|
1750
|
-
});
|
|
1846
|
+
idx.insert(rectToTree(rect, { zLayers: placed.zLayers }));
|
|
1751
1847
|
}
|
|
1752
1848
|
}
|
|
1753
1849
|
resizeSoftOverlaps(
|
|
@@ -1979,15 +2075,6 @@ function rectsToMeshNodes(rects) {
|
|
|
1979
2075
|
// lib/solvers/RectDiffExpansionSolver/RectDiffExpansionSolver.ts
|
|
1980
2076
|
import RBush4 from "rbush";
|
|
1981
2077
|
|
|
1982
|
-
// lib/utils/rectToTree.ts
|
|
1983
|
-
var rectToTree = (rect) => ({
|
|
1984
|
-
...rect,
|
|
1985
|
-
minX: rect.x,
|
|
1986
|
-
minY: rect.y,
|
|
1987
|
-
maxX: rect.x + rect.width,
|
|
1988
|
-
maxY: rect.y + rect.height
|
|
1989
|
-
});
|
|
1990
|
-
|
|
1991
2078
|
// lib/utils/sameTreeRect.ts
|
|
1992
2079
|
var sameTreeRect = (a, b) => a.minX === b.minX && a.minY === b.minY && a.maxX === b.maxX && a.maxY === b.maxY;
|
|
1993
2080
|
|
|
@@ -1996,148 +2083,116 @@ var RectDiffExpansionSolver = class extends BaseSolver4 {
|
|
|
1996
2083
|
constructor(input) {
|
|
1997
2084
|
super();
|
|
1998
2085
|
this.input = input;
|
|
1999
|
-
Object.assign(this, this.input.initialSnapshot);
|
|
2000
2086
|
}
|
|
2001
|
-
|
|
2002
|
-
srj;
|
|
2003
|
-
layerNames;
|
|
2004
|
-
layerCount;
|
|
2005
|
-
bounds;
|
|
2006
|
-
options;
|
|
2007
|
-
boardVoidRects;
|
|
2008
|
-
gridIndex;
|
|
2009
|
-
candidates;
|
|
2010
|
-
placed;
|
|
2011
|
-
placedIndexByLayer;
|
|
2012
|
-
expansionIndex;
|
|
2013
|
-
edgeAnalysisDone;
|
|
2014
|
-
totalSeedsThisGrid;
|
|
2015
|
-
consumedSeedsThisGrid;
|
|
2087
|
+
placedIndexByLayer = [];
|
|
2016
2088
|
_meshNodes = [];
|
|
2017
2089
|
_setup() {
|
|
2018
2090
|
this.stats = {
|
|
2019
|
-
gridIndex: this.gridIndex
|
|
2091
|
+
gridIndex: this.input.gridIndex
|
|
2020
2092
|
};
|
|
2021
|
-
if (this.input.obstacleIndexByLayer) {
|
|
2022
|
-
} else {
|
|
2023
|
-
const { zIndexByName } = buildZIndexMap(this.srj);
|
|
2024
|
-
this.input.obstacleIndexByLayer = Array.from(
|
|
2025
|
-
{ length: this.layerCount },
|
|
2026
|
-
() => new RBush4()
|
|
2027
|
-
);
|
|
2028
|
-
const insertObstacle = (rect, z) => {
|
|
2029
|
-
const tree = this.input.obstacleIndexByLayer[z];
|
|
2030
|
-
if (tree) tree.insert(rectToTree(rect));
|
|
2031
|
-
};
|
|
2032
|
-
for (const voidRect of this.boardVoidRects ?? []) {
|
|
2033
|
-
for (let z = 0; z < this.layerCount; z++) insertObstacle(voidRect, z);
|
|
2034
|
-
}
|
|
2035
|
-
for (const obstacle of this.srj.obstacles ?? []) {
|
|
2036
|
-
const rect = obstacleToXYRect(obstacle);
|
|
2037
|
-
if (!rect) continue;
|
|
2038
|
-
const zLayers = obstacle.zLayers?.length && obstacle.zLayers.length > 0 ? obstacle.zLayers : obstacleZs(obstacle, zIndexByName);
|
|
2039
|
-
zLayers.forEach((z) => {
|
|
2040
|
-
if (z >= 0 && z < this.layerCount) insertObstacle(rect, z);
|
|
2041
|
-
});
|
|
2042
|
-
}
|
|
2043
|
-
}
|
|
2044
2093
|
this.placedIndexByLayer = Array.from(
|
|
2045
|
-
{ length: this.layerCount },
|
|
2094
|
+
{ length: this.input.layerCount },
|
|
2046
2095
|
() => new RBush4()
|
|
2047
2096
|
);
|
|
2048
|
-
for (const placement of this.placed
|
|
2097
|
+
for (const placement of this.input.placed) {
|
|
2049
2098
|
for (const z of placement.zLayers) {
|
|
2050
|
-
const
|
|
2051
|
-
if (
|
|
2099
|
+
const placedIndex = this.placedIndexByLayer[z];
|
|
2100
|
+
if (placedIndex)
|
|
2101
|
+
placedIndex.insert(
|
|
2102
|
+
rectToTree(placement.rect, { zLayers: placement.zLayers })
|
|
2103
|
+
);
|
|
2052
2104
|
}
|
|
2053
2105
|
}
|
|
2054
2106
|
}
|
|
2055
2107
|
_step() {
|
|
2056
2108
|
if (this.solved) return;
|
|
2057
2109
|
this._stepExpansion();
|
|
2058
|
-
this.stats.gridIndex = this.gridIndex;
|
|
2059
|
-
this.stats.placed = this.placed.length;
|
|
2060
|
-
if (this.expansionIndex >= this.placed.length) {
|
|
2110
|
+
this.stats.gridIndex = this.input.gridIndex;
|
|
2111
|
+
this.stats.placed = this.input.placed.length;
|
|
2112
|
+
if (this.input.expansionIndex >= this.input.placed.length) {
|
|
2061
2113
|
this.finalizeIfNeeded();
|
|
2062
2114
|
}
|
|
2063
2115
|
}
|
|
2064
2116
|
_stepExpansion() {
|
|
2065
|
-
if (this.expansionIndex >= this.placed.length) {
|
|
2117
|
+
if (this.input.expansionIndex >= this.input.placed.length) {
|
|
2066
2118
|
return;
|
|
2067
2119
|
}
|
|
2068
|
-
const idx = this.expansionIndex;
|
|
2069
|
-
const p = this.placed[idx];
|
|
2070
|
-
const lastGrid = this.options.gridSizes[this.options.gridSizes.length - 1];
|
|
2071
|
-
const hardPlacedByLayer = allLayerNode({
|
|
2072
|
-
layerCount: this.layerCount,
|
|
2073
|
-
placed: this.placed
|
|
2074
|
-
});
|
|
2075
|
-
const hardBlockers = [];
|
|
2076
|
-
for (const z of p.zLayers) {
|
|
2077
|
-
const obstacleTree = this.input.obstacleIndexByLayer[z];
|
|
2078
|
-
if (obstacleTree) hardBlockers.push(...obstacleTree.all());
|
|
2079
|
-
hardBlockers.push(...hardPlacedByLayer[z] ?? []);
|
|
2080
|
-
}
|
|
2120
|
+
const idx = this.input.expansionIndex;
|
|
2121
|
+
const p = this.input.placed[idx];
|
|
2122
|
+
const lastGrid = this.input.options.gridSizes[this.input.options.gridSizes.length - 1];
|
|
2081
2123
|
const oldRect = p.rect;
|
|
2082
2124
|
const expanded = expandRectFromSeed({
|
|
2083
2125
|
startX: p.rect.x + p.rect.width / 2,
|
|
2084
2126
|
startY: p.rect.y + p.rect.height / 2,
|
|
2085
2127
|
gridSize: lastGrid,
|
|
2086
|
-
bounds: this.bounds,
|
|
2087
|
-
|
|
2128
|
+
bounds: this.input.bounds,
|
|
2129
|
+
obsticalIndexByLayer: this.input.obstacleIndexByLayer,
|
|
2130
|
+
placedIndexByLayer: this.placedIndexByLayer,
|
|
2088
2131
|
initialCellRatio: 0,
|
|
2089
2132
|
maxAspectRatio: null,
|
|
2090
|
-
minReq: { width: p.rect.width, height: p.rect.height }
|
|
2133
|
+
minReq: { width: p.rect.width, height: p.rect.height },
|
|
2134
|
+
zLayers: p.zLayers
|
|
2091
2135
|
});
|
|
2092
2136
|
if (expanded) {
|
|
2093
|
-
this.placed[idx] = { rect: expanded, zLayers: p.zLayers };
|
|
2137
|
+
this.input.placed[idx] = { rect: expanded, zLayers: p.zLayers };
|
|
2094
2138
|
for (const z of p.zLayers) {
|
|
2095
2139
|
const tree = this.placedIndexByLayer[z];
|
|
2096
2140
|
if (tree) {
|
|
2097
|
-
tree.remove(rectToTree(oldRect), sameTreeRect);
|
|
2098
|
-
tree.insert(rectToTree(expanded));
|
|
2141
|
+
tree.remove(rectToTree(oldRect, { zLayers: p.zLayers }), sameTreeRect);
|
|
2142
|
+
tree.insert(rectToTree(expanded, { zLayers: p.zLayers }));
|
|
2099
2143
|
}
|
|
2100
2144
|
}
|
|
2101
2145
|
resizeSoftOverlaps(
|
|
2102
2146
|
{
|
|
2103
|
-
layerCount: this.layerCount,
|
|
2104
|
-
placed: this.placed,
|
|
2105
|
-
options: this.options,
|
|
2147
|
+
layerCount: this.input.layerCount,
|
|
2148
|
+
placed: this.input.placed,
|
|
2149
|
+
options: this.input.options,
|
|
2106
2150
|
placedIndexByLayer: this.placedIndexByLayer
|
|
2107
2151
|
},
|
|
2108
2152
|
idx
|
|
2109
2153
|
);
|
|
2110
2154
|
}
|
|
2111
|
-
this.expansionIndex += 1;
|
|
2155
|
+
this.input.expansionIndex += 1;
|
|
2112
2156
|
}
|
|
2113
2157
|
finalizeIfNeeded() {
|
|
2114
2158
|
if (this.solved) return;
|
|
2115
2159
|
const rects = finalizeRects({
|
|
2116
|
-
placed: this.placed,
|
|
2117
|
-
srj: this.srj,
|
|
2118
|
-
boardVoidRects: this.boardVoidRects
|
|
2160
|
+
placed: this.input.placed,
|
|
2161
|
+
srj: this.input.srj,
|
|
2162
|
+
boardVoidRects: this.input.boardVoidRects
|
|
2119
2163
|
});
|
|
2120
2164
|
this._meshNodes = rectsToMeshNodes(rects);
|
|
2121
2165
|
this.solved = true;
|
|
2122
2166
|
}
|
|
2123
2167
|
computeProgress() {
|
|
2124
2168
|
if (this.solved) return 1;
|
|
2125
|
-
const grids = this.options.gridSizes.length;
|
|
2169
|
+
const grids = this.input.options.gridSizes.length;
|
|
2126
2170
|
const base = grids / (grids + 1);
|
|
2127
|
-
const denom = Math.max(1, this.placed.length);
|
|
2128
|
-
const frac = denom ? this.expansionIndex / denom : 1;
|
|
2171
|
+
const denom = Math.max(1, this.input.placed.length);
|
|
2172
|
+
const frac = denom ? this.input.expansionIndex / denom : 1;
|
|
2129
2173
|
return Math.min(0.999, base + frac * (1 / (grids + 1)));
|
|
2130
2174
|
}
|
|
2131
2175
|
getOutput() {
|
|
2132
|
-
if (
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2176
|
+
if (this.solved) return { meshNodes: this._meshNodes };
|
|
2177
|
+
const previewNodes = this.input.placed.map(
|
|
2178
|
+
(placement, idx) => ({
|
|
2179
|
+
capacityMeshNodeId: `expand-preview-${idx}`,
|
|
2180
|
+
center: {
|
|
2181
|
+
x: placement.rect.x + placement.rect.width / 2,
|
|
2182
|
+
y: placement.rect.y + placement.rect.height / 2
|
|
2183
|
+
},
|
|
2184
|
+
width: placement.rect.width,
|
|
2185
|
+
height: placement.rect.height,
|
|
2186
|
+
availableZ: placement.zLayers.slice(),
|
|
2187
|
+
layer: `z${placement.zLayers.join(",")}`
|
|
2188
|
+
})
|
|
2189
|
+
);
|
|
2190
|
+
return { meshNodes: previewNodes };
|
|
2136
2191
|
}
|
|
2137
2192
|
/** Simple visualization of expanded placements. */
|
|
2138
2193
|
visualize() {
|
|
2139
2194
|
const rects = [];
|
|
2140
|
-
for (const placement of this.placed ?? []) {
|
|
2195
|
+
for (const placement of this.input.placed ?? []) {
|
|
2141
2196
|
rects.push({
|
|
2142
2197
|
center: {
|
|
2143
2198
|
x: placement.rect.x + placement.rect.width / 2,
|
|
@@ -2187,7 +2242,8 @@ var buildObstacleIndexesByLayer = (params) => {
|
|
|
2187
2242
|
minX: rect.x,
|
|
2188
2243
|
minY: rect.y,
|
|
2189
2244
|
maxX: rect.x + rect.width,
|
|
2190
|
-
maxY: rect.y + rect.height
|
|
2245
|
+
maxY: rect.y + rect.height,
|
|
2246
|
+
zLayers: [z]
|
|
2191
2247
|
};
|
|
2192
2248
|
obstacleIndexByLayer[z]?.insert(treeRect);
|
|
2193
2249
|
};
|
|
@@ -2243,15 +2299,30 @@ var RectDiffGridSolverPipeline = class extends BasePipelineSolver2 {
|
|
|
2243
2299
|
definePipelineStep2(
|
|
2244
2300
|
"rectDiffExpansionSolver",
|
|
2245
2301
|
RectDiffExpansionSolver,
|
|
2246
|
-
(pipeline) =>
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
boardVoidRects: pipeline.inputProblem.boardVoidRects ?? []
|
|
2251
|
-
},
|
|
2252
|
-
obstacleIndexByLayer: pipeline.obstacleIndexByLayer
|
|
2302
|
+
(pipeline) => {
|
|
2303
|
+
const output = pipeline.rectDiffSeedingSolver?.getOutput();
|
|
2304
|
+
if (!output) {
|
|
2305
|
+
throw new Error("RectDiffSeedingSolver did not produce output");
|
|
2253
2306
|
}
|
|
2254
|
-
|
|
2307
|
+
return [
|
|
2308
|
+
{
|
|
2309
|
+
srj: pipeline.inputProblem.simpleRouteJson,
|
|
2310
|
+
layerNames: output.layerNames ?? [],
|
|
2311
|
+
boardVoidRects: pipeline.inputProblem.boardVoidRects ?? [],
|
|
2312
|
+
layerCount: pipeline.inputProblem.simpleRouteJson.layerCount,
|
|
2313
|
+
bounds: output.bounds,
|
|
2314
|
+
candidates: output.candidates,
|
|
2315
|
+
consumedSeedsThisGrid: output.placed.length,
|
|
2316
|
+
totalSeedsThisGrid: output.candidates.length,
|
|
2317
|
+
placed: output.placed,
|
|
2318
|
+
edgeAnalysisDone: output.edgeAnalysisDone,
|
|
2319
|
+
gridIndex: output.gridIndex,
|
|
2320
|
+
expansionIndex: output.expansionIndex,
|
|
2321
|
+
obstacleIndexByLayer: pipeline.obstacleIndexByLayer,
|
|
2322
|
+
options: output.options
|
|
2323
|
+
}
|
|
2324
|
+
];
|
|
2325
|
+
}
|
|
2255
2326
|
)
|
|
2256
2327
|
];
|
|
2257
2328
|
getConstructorParams() {
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import RBush from "rbush"
|
|
2
|
-
import type {
|
|
3
|
-
RectDiffExpansionSolverInput,
|
|
4
|
-
RectDiffExpansionSolverSnapshot,
|
|
5
|
-
} from "../solvers/RectDiffExpansionSolver/RectDiffExpansionSolver"
|
|
2
|
+
import type { RectDiffExpansionSolverInput } from "../solvers/RectDiffExpansionSolver/RectDiffExpansionSolver"
|
|
6
3
|
import type { SimpleRouteJson } from "../types/srj-types"
|
|
7
4
|
import type { XYRect } from "../rectdiff-types"
|
|
8
5
|
import type { RTreeRect } from "lib/types/capacity-mesh-types"
|
|
@@ -34,7 +31,7 @@ export const createTwoNodeExpansionInput = (): RectDiffExpansionSolverInput => {
|
|
|
34
31
|
)
|
|
35
32
|
// Start with all-empty obstacle indexes for a "clean" scenario
|
|
36
33
|
|
|
37
|
-
|
|
34
|
+
return {
|
|
38
35
|
srj,
|
|
39
36
|
layerNames: ["top"],
|
|
40
37
|
layerCount,
|
|
@@ -57,10 +54,6 @@ export const createTwoNodeExpansionInput = (): RectDiffExpansionSolverInput => {
|
|
|
57
54
|
edgeAnalysisDone: true,
|
|
58
55
|
totalSeedsThisGrid: 0,
|
|
59
56
|
consumedSeedsThisGrid: 0,
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
return {
|
|
63
|
-
initialSnapshot,
|
|
64
57
|
obstacleIndexByLayer,
|
|
65
58
|
}
|
|
66
59
|
}
|