@tscircuit/capacity-autorouter 0.0.30 → 0.0.31
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 +58 -2
- package/dist/index.js +246 -97
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -118,12 +118,50 @@ declare class CapacityMeshEdgeSolver extends BaseSolver {
|
|
|
118
118
|
visualize(): GraphicsObject;
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
+
type BucketCoordinate$1 = `${number}x${number}`;
|
|
122
|
+
declare class ObstacleTree {
|
|
123
|
+
obstacles: Obstacle[];
|
|
124
|
+
buckets: Map<BucketCoordinate$1, [Obstacle, number][]>;
|
|
125
|
+
CELL_SIZE: number;
|
|
126
|
+
constructor(obstacles: Obstacle[]);
|
|
127
|
+
getBucketKey(x: number, y: number): BucketCoordinate$1;
|
|
128
|
+
getNodesInArea(centerX: number, centerY: number, width: number, height: number): Obstacle[];
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
interface Target$1 {
|
|
132
|
+
x: number;
|
|
133
|
+
y: number;
|
|
134
|
+
bounds: {
|
|
135
|
+
minX: number;
|
|
136
|
+
minY: number;
|
|
137
|
+
maxX: number;
|
|
138
|
+
maxY: number;
|
|
139
|
+
};
|
|
140
|
+
connectionName: string;
|
|
141
|
+
availableZ: number[];
|
|
142
|
+
}
|
|
143
|
+
type BucketCoordinate = `${number}x${number}`;
|
|
144
|
+
declare class TargetTree {
|
|
145
|
+
targets: Target$1[];
|
|
146
|
+
buckets: Map<BucketCoordinate, [Target$1, number][]>;
|
|
147
|
+
CELL_SIZE: number;
|
|
148
|
+
constructor(targets: Target$1[]);
|
|
149
|
+
getBucketKey(x: number, y: number): BucketCoordinate;
|
|
150
|
+
getTargetsInArea(centerX: number, centerY: number, width: number, height: number): Target$1[];
|
|
151
|
+
}
|
|
152
|
+
|
|
121
153
|
interface CapacityMeshNodeSolverOptions$1 {
|
|
122
154
|
capacityDepth?: number;
|
|
123
155
|
}
|
|
124
156
|
interface Target {
|
|
125
157
|
x: number;
|
|
126
158
|
y: number;
|
|
159
|
+
bounds: {
|
|
160
|
+
minX: number;
|
|
161
|
+
minY: number;
|
|
162
|
+
maxX: number;
|
|
163
|
+
maxY: number;
|
|
164
|
+
};
|
|
127
165
|
connectionName: string;
|
|
128
166
|
availableZ: number[];
|
|
129
167
|
}
|
|
@@ -136,7 +174,10 @@ declare class CapacityMeshNodeSolver extends BaseSolver {
|
|
|
136
174
|
layerCount: number;
|
|
137
175
|
MAX_DEPTH: number;
|
|
138
176
|
targets: Target[];
|
|
177
|
+
targetTree: TargetTree;
|
|
178
|
+
obstacleTree: ObstacleTree;
|
|
139
179
|
constructor(srj: SimpleRouteJson, opts?: CapacityMeshNodeSolverOptions$1);
|
|
180
|
+
computeTargets(): Target[];
|
|
140
181
|
_nextNodeCounter: number;
|
|
141
182
|
getNextNodeId(): string;
|
|
142
183
|
getCapacityFromDepth(depth: number): number;
|
|
@@ -965,6 +1006,11 @@ interface UnravelSection {
|
|
|
965
1006
|
segmentPairsInNode: Map<CapacityMeshNodeId, Array<[SegmentPointId, SegmentPointId]>>;
|
|
966
1007
|
segmentPointsInNode: Map<CapacityMeshNodeId, SegmentPointId[]>;
|
|
967
1008
|
segmentPointsInSegment: Map<SegmentId, SegmentPointId[]>;
|
|
1009
|
+
originalPointMap: Map<SegmentPointId, {
|
|
1010
|
+
x: number;
|
|
1011
|
+
y: number;
|
|
1012
|
+
z: number;
|
|
1013
|
+
}>;
|
|
968
1014
|
}
|
|
969
1015
|
interface UnravelChangeLayerOperation {
|
|
970
1016
|
type: "change_layer";
|
|
@@ -1013,6 +1059,12 @@ type UnravelCandidate = {
|
|
|
1013
1059
|
f: number;
|
|
1014
1060
|
};
|
|
1015
1061
|
|
|
1062
|
+
type SegmentPointMapAndReverseMaps = {
|
|
1063
|
+
segmentPointMap: SegmentPointMap;
|
|
1064
|
+
nodeToSegmentPointMap: Map<CapacityMeshNodeId, SegmentPointId[]>;
|
|
1065
|
+
segmentToSegmentPointMap: Map<SegmentId, SegmentPointId[]>;
|
|
1066
|
+
};
|
|
1067
|
+
|
|
1016
1068
|
/**
|
|
1017
1069
|
* The UntangleSectionSolver optimizes a section of connected capacity nodes
|
|
1018
1070
|
* with their deduplicated segments.
|
|
@@ -1068,8 +1120,10 @@ declare class UnravelSectionSolver extends BaseSolver {
|
|
|
1068
1120
|
nodeIdToSegmentIds: Map<CapacityMeshNodeId, CapacityMeshNodeId[]>;
|
|
1069
1121
|
segmentIdToNodeIds: Map<CapacityMeshNodeId, CapacityMeshNodeId[]>;
|
|
1070
1122
|
segmentPointMap?: SegmentPointMap;
|
|
1123
|
+
nodeToSegmentPointMap?: Map<CapacityMeshNodeId, SegmentPointId[]>;
|
|
1124
|
+
segmentToSegmentPointMap?: Map<SegmentId, SegmentPointId[]>;
|
|
1071
1125
|
});
|
|
1072
|
-
createUnravelSection(
|
|
1126
|
+
createUnravelSection(largeSpMaps?: SegmentPointMapAndReverseMaps): UnravelSection;
|
|
1073
1127
|
createInitialCandidate(): UnravelCandidate;
|
|
1074
1128
|
get nextCandidate(): UnravelCandidate | null;
|
|
1075
1129
|
getPointInCandidate(candidate: UnravelCandidate, segmentPointId: SegmentPointId): {
|
|
@@ -1085,7 +1139,7 @@ declare class UnravelSectionSolver extends BaseSolver {
|
|
|
1085
1139
|
operationsPerformed: number;
|
|
1086
1140
|
operation: UnravelOperation;
|
|
1087
1141
|
}): number;
|
|
1088
|
-
|
|
1142
|
+
getUnexploredNeighborByApplyingOperation(currentCandidate: UnravelCandidate, operation: UnravelOperation): UnravelCandidate | null;
|
|
1089
1143
|
getNeighborOperationsForCandidate(candidate: UnravelCandidate): UnravelOperation[];
|
|
1090
1144
|
getNeighbors(candidate: UnravelCandidate): UnravelCandidate[];
|
|
1091
1145
|
_step(): void;
|
|
@@ -1098,6 +1152,8 @@ declare class UnravelMultiSectionSolver extends BaseSolver {
|
|
|
1098
1152
|
dedupedSegments: SegmentWithAssignedPoints[];
|
|
1099
1153
|
nodeIdToSegmentIds: Map<CapacityMeshNodeId, CapacityMeshNodeId[]>;
|
|
1100
1154
|
segmentIdToNodeIds: Map<CapacityMeshNodeId, CapacityMeshNodeId[]>;
|
|
1155
|
+
nodeToSegmentPointMap: Map<CapacityMeshNodeId, SegmentPointId[]>;
|
|
1156
|
+
segmentToSegmentPointMap: Map<SegmentId, SegmentPointId[]>;
|
|
1101
1157
|
colorMap: Record<string, string>;
|
|
1102
1158
|
tunedNodeCapacityMap: Map<CapacityMeshNodeId, number>;
|
|
1103
1159
|
MAX_NODE_ATTEMPTS: number;
|
package/dist/index.js
CHANGED
|
@@ -918,24 +918,6 @@ var safeTransparentize = (color, amount) => {
|
|
|
918
918
|
}
|
|
919
919
|
};
|
|
920
920
|
|
|
921
|
-
// lib/utils/isPointInRect.ts
|
|
922
|
-
function isPointInRect(point, rect) {
|
|
923
|
-
return point.x >= rect.center.x - rect.width / 2 && point.x <= rect.center.x + rect.width / 2 && point.y >= rect.center.y - rect.height / 2 && point.y <= rect.center.y + rect.height / 2;
|
|
924
|
-
}
|
|
925
|
-
|
|
926
|
-
// lib/utils/doRectsOverlap.ts
|
|
927
|
-
function doRectsOverlap(rect1, rect2) {
|
|
928
|
-
const rect1Left = rect1.center.x - rect1.width / 2;
|
|
929
|
-
const rect1Right = rect1.center.x + rect1.width / 2;
|
|
930
|
-
const rect1Top = rect1.center.y - rect1.height / 2;
|
|
931
|
-
const rect1Bottom = rect1.center.y + rect1.height / 2;
|
|
932
|
-
const rect2Left = rect2.center.x - rect2.width / 2;
|
|
933
|
-
const rect2Right = rect2.center.x + rect2.width / 2;
|
|
934
|
-
const rect2Top = rect2.center.y - rect2.height / 2;
|
|
935
|
-
const rect2Bottom = rect2.center.y + rect2.height / 2;
|
|
936
|
-
return rect1Left <= rect2Right && rect1Right >= rect2Left && rect1Top <= rect2Bottom && rect1Bottom >= rect2Top;
|
|
937
|
-
}
|
|
938
|
-
|
|
939
921
|
// lib/utils/mapLayerNameToZ.ts
|
|
940
922
|
var mapLayerNameToZ = (layerName, layerCount) => {
|
|
941
923
|
if (layerName === "top") return 0;
|
|
@@ -966,6 +948,108 @@ var calculateOptimalCapacityDepth = (initialWidth, targetMinCapacity = 0.5, maxD
|
|
|
966
948
|
return Math.max(1, depth);
|
|
967
949
|
};
|
|
968
950
|
|
|
951
|
+
// lib/data-structures/ObstacleTree.ts
|
|
952
|
+
var ObstacleTree = class {
|
|
953
|
+
constructor(obstacles) {
|
|
954
|
+
this.obstacles = obstacles;
|
|
955
|
+
this.buckets = /* @__PURE__ */ new Map();
|
|
956
|
+
for (let i = 0; i < obstacles.length; i++) {
|
|
957
|
+
const obstacle = obstacles[i];
|
|
958
|
+
const nodeMinX = obstacle.center.x - obstacle.width / 2;
|
|
959
|
+
const nodeMinY = obstacle.center.y - obstacle.height / 2;
|
|
960
|
+
const nodeMaxX = obstacle.center.x + obstacle.width / 2;
|
|
961
|
+
const nodeMaxY = obstacle.center.y + obstacle.height / 2;
|
|
962
|
+
for (let x = nodeMinX; x <= nodeMaxX; x += this.CELL_SIZE) {
|
|
963
|
+
for (let y = nodeMinY; y <= nodeMaxY; y += this.CELL_SIZE) {
|
|
964
|
+
const bucketKey = this.getBucketKey(x, y);
|
|
965
|
+
const bucket = this.buckets.get(bucketKey);
|
|
966
|
+
if (!bucket) {
|
|
967
|
+
this.buckets.set(bucketKey, [[obstacle, i]]);
|
|
968
|
+
} else {
|
|
969
|
+
bucket.push([obstacle, i]);
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
buckets;
|
|
976
|
+
CELL_SIZE = 0.4;
|
|
977
|
+
getBucketKey(x, y) {
|
|
978
|
+
return `${Math.floor(x / this.CELL_SIZE)}x${Math.floor(y / this.CELL_SIZE)}`;
|
|
979
|
+
}
|
|
980
|
+
getNodesInArea(centerX, centerY, width, height) {
|
|
981
|
+
const obstacles = [];
|
|
982
|
+
const alreadyAddedObstacles = /* @__PURE__ */ new Set();
|
|
983
|
+
const minX = centerX - width / 2;
|
|
984
|
+
const minY = centerY - height / 2;
|
|
985
|
+
const maxX = centerX + width / 2;
|
|
986
|
+
const maxY = centerY + height / 2;
|
|
987
|
+
for (let x = minX; x <= maxX; x += this.CELL_SIZE) {
|
|
988
|
+
for (let y = minY; y <= maxY; y += this.CELL_SIZE) {
|
|
989
|
+
const bucketKey = this.getBucketKey(x, y);
|
|
990
|
+
const bucket = this.buckets.get(bucketKey) || [];
|
|
991
|
+
for (const obstacleWithIndex of bucket) {
|
|
992
|
+
if (alreadyAddedObstacles.has(obstacleWithIndex[1])) continue;
|
|
993
|
+
alreadyAddedObstacles.add(obstacleWithIndex[1]);
|
|
994
|
+
obstacles.push(obstacleWithIndex[0]);
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
return obstacles;
|
|
999
|
+
}
|
|
1000
|
+
};
|
|
1001
|
+
|
|
1002
|
+
// lib/data-structures/TargetTree.ts
|
|
1003
|
+
var TargetTree = class {
|
|
1004
|
+
constructor(targets) {
|
|
1005
|
+
this.targets = targets;
|
|
1006
|
+
this.buckets = /* @__PURE__ */ new Map();
|
|
1007
|
+
for (let i = 0; i < targets.length; i++) {
|
|
1008
|
+
const target = targets[i];
|
|
1009
|
+
const targetBucketMinX = Math.floor(target.bounds.minX / this.CELL_SIZE) * this.CELL_SIZE;
|
|
1010
|
+
const targetBucketMinY = Math.floor(target.bounds.minY / this.CELL_SIZE) * this.CELL_SIZE;
|
|
1011
|
+
const targetMaxX = target.bounds.maxX;
|
|
1012
|
+
const targetMaxY = target.bounds.maxY;
|
|
1013
|
+
for (let x = targetBucketMinX; x <= targetMaxX; x += this.CELL_SIZE) {
|
|
1014
|
+
for (let y = targetBucketMinY; y <= targetMaxY; y += this.CELL_SIZE) {
|
|
1015
|
+
const bucketKey = this.getBucketKey(x, y);
|
|
1016
|
+
const bucket = this.buckets.get(bucketKey);
|
|
1017
|
+
if (!bucket) {
|
|
1018
|
+
this.buckets.set(bucketKey, [[target, i]]);
|
|
1019
|
+
} else {
|
|
1020
|
+
bucket.push([target, i]);
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
buckets;
|
|
1027
|
+
CELL_SIZE = 5;
|
|
1028
|
+
getBucketKey(x, y) {
|
|
1029
|
+
return `${Math.floor(x / this.CELL_SIZE)}x${Math.floor(y / this.CELL_SIZE)}`;
|
|
1030
|
+
}
|
|
1031
|
+
getTargetsInArea(centerX, centerY, width, height) {
|
|
1032
|
+
const targets = [];
|
|
1033
|
+
const alreadyAddedTargets = /* @__PURE__ */ new Set();
|
|
1034
|
+
const minX = Math.floor((centerX - width / 2) / this.CELL_SIZE) * this.CELL_SIZE;
|
|
1035
|
+
const minY = Math.floor((centerY - height / 2) / this.CELL_SIZE) * this.CELL_SIZE;
|
|
1036
|
+
const maxX = centerX + width / 2;
|
|
1037
|
+
const maxY = centerY + height / 2;
|
|
1038
|
+
for (let x = minX; x <= maxX; x += this.CELL_SIZE) {
|
|
1039
|
+
for (let y = minY; y <= maxY; y += this.CELL_SIZE) {
|
|
1040
|
+
const bucketKey = this.getBucketKey(x, y);
|
|
1041
|
+
const bucket = this.buckets.get(bucketKey) || [];
|
|
1042
|
+
for (const targetWithIndex of bucket) {
|
|
1043
|
+
if (alreadyAddedTargets.has(targetWithIndex[1])) continue;
|
|
1044
|
+
alreadyAddedTargets.add(targetWithIndex[1]);
|
|
1045
|
+
targets.push(targetWithIndex[0]);
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
return targets;
|
|
1050
|
+
}
|
|
1051
|
+
};
|
|
1052
|
+
|
|
969
1053
|
// lib/solvers/CapacityMeshSolver/CapacityMeshNodeSolver1.ts
|
|
970
1054
|
var CapacityMeshNodeSolver = class extends BaseSolver {
|
|
971
1055
|
constructor(srj, opts = {}) {
|
|
@@ -1009,13 +1093,9 @@ var CapacityMeshNodeSolver = class extends BaseSolver {
|
|
|
1009
1093
|
];
|
|
1010
1094
|
this.finishedNodes = [];
|
|
1011
1095
|
this.nodeToXYOverlappingObstaclesMap = /* @__PURE__ */ new Map();
|
|
1012
|
-
this.
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
connectionName: c.name,
|
|
1016
|
-
availableZ: p.layer === "top" ? [0] : [1]
|
|
1017
|
-
}))
|
|
1018
|
-
);
|
|
1096
|
+
this.obstacleTree = new ObstacleTree(this.srj.obstacles);
|
|
1097
|
+
this.targets = this.computeTargets();
|
|
1098
|
+
this.targetTree = new TargetTree(this.targets);
|
|
1019
1099
|
}
|
|
1020
1100
|
unfinishedNodes;
|
|
1021
1101
|
finishedNodes;
|
|
@@ -1024,6 +1104,40 @@ var CapacityMeshNodeSolver = class extends BaseSolver {
|
|
|
1024
1104
|
// targetObstacleMap: Record<string, { obstacle: Obstacle, node: CapacityMeshNode }>
|
|
1025
1105
|
MAX_DEPTH = 4;
|
|
1026
1106
|
targets;
|
|
1107
|
+
targetTree;
|
|
1108
|
+
obstacleTree;
|
|
1109
|
+
computeTargets() {
|
|
1110
|
+
const targets = [];
|
|
1111
|
+
for (const conn of this.srj.connections) {
|
|
1112
|
+
for (const ptc of conn.pointsToConnect) {
|
|
1113
|
+
const obstacles = this.obstacleTree.getNodesInArea(ptc.x, ptc.y, 0.01, 0.01).filter(
|
|
1114
|
+
(o) => o.zLayers.some((z) => ptc.layer === "top" ? z === 0 : z === 1)
|
|
1115
|
+
);
|
|
1116
|
+
let bounds = {
|
|
1117
|
+
minX: ptc.x - 5e-3,
|
|
1118
|
+
minY: ptc.y - 5e-3,
|
|
1119
|
+
maxX: ptc.x + 5e-3,
|
|
1120
|
+
maxY: ptc.y + 5e-3
|
|
1121
|
+
};
|
|
1122
|
+
if (obstacles.length > 0) {
|
|
1123
|
+
bounds = {
|
|
1124
|
+
minX: Math.min(...obstacles.map((o) => o.center.x - o.width / 2)),
|
|
1125
|
+
minY: Math.min(...obstacles.map((o) => o.center.y - o.height / 2)),
|
|
1126
|
+
maxX: Math.max(...obstacles.map((o) => o.center.x + o.width / 2)),
|
|
1127
|
+
maxY: Math.max(...obstacles.map((o) => o.center.y + o.height / 2))
|
|
1128
|
+
};
|
|
1129
|
+
}
|
|
1130
|
+
const target = {
|
|
1131
|
+
...ptc,
|
|
1132
|
+
connectionName: conn.name,
|
|
1133
|
+
availableZ: ptc.layer === "top" ? [0] : [1],
|
|
1134
|
+
bounds
|
|
1135
|
+
};
|
|
1136
|
+
targets.push(target);
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
return targets;
|
|
1140
|
+
}
|
|
1027
1141
|
_nextNodeCounter = 0;
|
|
1028
1142
|
getNextNodeId() {
|
|
1029
1143
|
return `cn${this._nextNodeCounter++}`;
|
|
@@ -1032,18 +1146,17 @@ var CapacityMeshNodeSolver = class extends BaseSolver {
|
|
|
1032
1146
|
return (this.MAX_DEPTH - depth + 1) ** 2;
|
|
1033
1147
|
}
|
|
1034
1148
|
getTargetIfNodeContainsTarget(node) {
|
|
1035
|
-
const
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
if (target.x >= node.center.x - node.width / 2 && target.x <= node.center.x + node.width / 2 && target.y >= node.center.y - node.height / 2 && target.y <= node.center.y + node.height / 2) {
|
|
1149
|
+
const nearbyTargets = node.width > this.targetTree.CELL_SIZE * 4 ? this.targets : this.targetTree.getTargetsInArea(
|
|
1150
|
+
node.center.x,
|
|
1151
|
+
node.center.y,
|
|
1152
|
+
node.width,
|
|
1153
|
+
node.height
|
|
1154
|
+
);
|
|
1155
|
+
for (const target of nearbyTargets) {
|
|
1156
|
+
if (
|
|
1157
|
+
// Check if the node and target bounds overlap
|
|
1158
|
+
target.bounds.minX <= node.center.x + node.width / 2 && target.bounds.maxX >= node.center.x - node.width / 2 && target.bounds.minY <= node.center.y + node.height / 2 && target.bounds.maxY >= node.center.y - node.height / 2 && target.availableZ.some((z) => node.availableZ.includes(z))
|
|
1159
|
+
) {
|
|
1047
1160
|
return target;
|
|
1048
1161
|
}
|
|
1049
1162
|
}
|
|
@@ -3791,19 +3904,14 @@ var hasZRangeOverlap = (A_z1, A_z2, B_z1, B_z2) => {
|
|
|
3791
3904
|
// lib/solvers/UnravelSolver/getIssuesInSection.ts
|
|
3792
3905
|
var getIssuesInSection = (section, nodeMap, pointModifications, connMap) => {
|
|
3793
3906
|
const issues = [];
|
|
3794
|
-
const points =
|
|
3795
|
-
for (const
|
|
3796
|
-
|
|
3797
|
-
|
|
3798
|
-
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
|
|
3802
|
-
y: modPoint?.y ?? ogPoint.y,
|
|
3803
|
-
z: modPoint?.z ?? ogPoint.z
|
|
3804
|
-
});
|
|
3805
|
-
}
|
|
3806
|
-
}
|
|
3907
|
+
const points = new Map(section.originalPointMap);
|
|
3908
|
+
for (const [segmentPointId, modPoint] of pointModifications.entries()) {
|
|
3909
|
+
const ogPoint = points.get(segmentPointId);
|
|
3910
|
+
points.set(segmentPointId, {
|
|
3911
|
+
x: modPoint.x ?? ogPoint.x,
|
|
3912
|
+
y: modPoint.y ?? ogPoint.y,
|
|
3913
|
+
z: modPoint.z ?? ogPoint.z
|
|
3914
|
+
});
|
|
3807
3915
|
}
|
|
3808
3916
|
for (const nodeId of section.allNodeIds) {
|
|
3809
3917
|
const node = nodeMap.get(nodeId);
|
|
@@ -3928,11 +4036,14 @@ var applyOperationToPointModifications = (pointModifications, operation, getPoin
|
|
|
3928
4036
|
|
|
3929
4037
|
// lib/solvers/UnravelSolver/createSegmentPointMap.ts
|
|
3930
4038
|
var createSegmentPointMap = (dedupedSegments, segmentIdToNodeIds) => {
|
|
4039
|
+
const segmentPointMap = /* @__PURE__ */ new Map();
|
|
4040
|
+
const nodeToSegmentPointMap = /* @__PURE__ */ new Map();
|
|
4041
|
+
const segmentToSegmentPointMap = /* @__PURE__ */ new Map();
|
|
3931
4042
|
const segmentPoints = [];
|
|
3932
4043
|
let highestSegmentPointId = 0;
|
|
3933
4044
|
for (const segment of dedupedSegments) {
|
|
3934
4045
|
for (const point of segment.assignedPoints) {
|
|
3935
|
-
|
|
4046
|
+
const sp = {
|
|
3936
4047
|
segmentPointId: `SP${highestSegmentPointId++}`,
|
|
3937
4048
|
segmentId: segment.nodePortSegmentId,
|
|
3938
4049
|
capacityMeshNodeIds: segmentIdToNodeIds.get(
|
|
@@ -3943,14 +4054,26 @@ var createSegmentPointMap = (dedupedSegments, segmentIdToNodeIds) => {
|
|
|
3943
4054
|
y: point.point.y,
|
|
3944
4055
|
z: point.point.z,
|
|
3945
4056
|
directlyConnectedSegmentPointIds: []
|
|
3946
|
-
}
|
|
4057
|
+
};
|
|
4058
|
+
segmentPointMap.set(sp.segmentPointId, sp);
|
|
4059
|
+
for (const nodeId of sp.capacityMeshNodeIds) {
|
|
4060
|
+
nodeToSegmentPointMap.set(nodeId, [
|
|
4061
|
+
...nodeToSegmentPointMap.get(nodeId) ?? [],
|
|
4062
|
+
sp.segmentPointId
|
|
4063
|
+
]);
|
|
4064
|
+
}
|
|
4065
|
+
segmentToSegmentPointMap.set(segment.nodePortSegmentId, [
|
|
4066
|
+
...segmentToSegmentPointMap.get(segment.nodePortSegmentId) ?? [],
|
|
4067
|
+
sp.segmentPointId
|
|
4068
|
+
]);
|
|
4069
|
+
segmentPoints.push(sp);
|
|
3947
4070
|
}
|
|
3948
4071
|
}
|
|
3949
|
-
|
|
3950
|
-
|
|
3951
|
-
|
|
3952
|
-
|
|
3953
|
-
|
|
4072
|
+
return {
|
|
4073
|
+
segmentPointMap,
|
|
4074
|
+
nodeToSegmentPointMap,
|
|
4075
|
+
segmentToSegmentPointMap
|
|
4076
|
+
};
|
|
3954
4077
|
};
|
|
3955
4078
|
|
|
3956
4079
|
// lib/solvers/UnravelSolver/UnravelSectionSolver.ts
|
|
@@ -3989,7 +4112,11 @@ var UnravelSectionSolver = class extends BaseSolver {
|
|
|
3989
4112
|
this.segmentIdToNodeIds = params.segmentIdToNodeIds;
|
|
3990
4113
|
this.rootNodeId = params.rootNodeId;
|
|
3991
4114
|
this.colorMap = params.colorMap ?? {};
|
|
3992
|
-
this.unravelSection = this.createUnravelSection(
|
|
4115
|
+
this.unravelSection = this.createUnravelSection({
|
|
4116
|
+
segmentPointMap: params.segmentPointMap,
|
|
4117
|
+
nodeToSegmentPointMap: params.nodeToSegmentPointMap,
|
|
4118
|
+
segmentToSegmentPointMap: params.segmentToSegmentPointMap
|
|
4119
|
+
});
|
|
3993
4120
|
this.tunedNodeCapacityMap = /* @__PURE__ */ new Map();
|
|
3994
4121
|
for (const nodeId of this.unravelSection.allNodeIds) {
|
|
3995
4122
|
this.tunedNodeCapacityMap.set(
|
|
@@ -4000,38 +4127,43 @@ var UnravelSectionSolver = class extends BaseSolver {
|
|
|
4000
4127
|
this.originalCandidate = this.createInitialCandidate();
|
|
4001
4128
|
this.candidates = [this.originalCandidate];
|
|
4002
4129
|
}
|
|
4003
|
-
createUnravelSection(
|
|
4130
|
+
createUnravelSection(largeSpMaps) {
|
|
4004
4131
|
const mutableNodeIds = getNodesNearNode({
|
|
4005
4132
|
nodeId: this.rootNodeId,
|
|
4006
4133
|
nodeIdToSegmentIds: this.nodeIdToSegmentIds,
|
|
4007
4134
|
segmentIdToNodeIds: this.segmentIdToNodeIds,
|
|
4008
4135
|
hops: this.MUTABLE_HOPS
|
|
4009
4136
|
});
|
|
4010
|
-
const
|
|
4137
|
+
const allSectionNodeIds = getNodesNearNode({
|
|
4011
4138
|
nodeId: this.rootNodeId,
|
|
4012
4139
|
nodeIdToSegmentIds: this.nodeIdToSegmentIds,
|
|
4013
4140
|
segmentIdToNodeIds: this.segmentIdToNodeIds,
|
|
4014
4141
|
hops: this.MUTABLE_HOPS + 1
|
|
4015
4142
|
});
|
|
4016
4143
|
const immutableNodeIds = Array.from(
|
|
4017
|
-
new Set(
|
|
4144
|
+
new Set(allSectionNodeIds).difference(new Set(mutableNodeIds))
|
|
4018
4145
|
);
|
|
4019
|
-
if (!segmentPointMap) {
|
|
4020
|
-
|
|
4146
|
+
if (!largeSpMaps?.segmentPointMap) {
|
|
4147
|
+
largeSpMaps = createSegmentPointMap(
|
|
4021
4148
|
this.dedupedSegments,
|
|
4022
4149
|
this.segmentIdToNodeIds
|
|
4023
4150
|
);
|
|
4024
4151
|
}
|
|
4025
|
-
const segmentPoints = Array.from(segmentPointMap.values());
|
|
4026
4152
|
const segmentPointsInNode = /* @__PURE__ */ new Map();
|
|
4027
|
-
for (const
|
|
4028
|
-
|
|
4029
|
-
|
|
4030
|
-
|
|
4031
|
-
|
|
4032
|
-
|
|
4153
|
+
for (const nodeId of allSectionNodeIds) {
|
|
4154
|
+
segmentPointsInNode.set(
|
|
4155
|
+
nodeId,
|
|
4156
|
+
largeSpMaps.nodeToSegmentPointMap.get(nodeId)
|
|
4157
|
+
);
|
|
4158
|
+
}
|
|
4159
|
+
const sectionPointMap = /* @__PURE__ */ new Map();
|
|
4160
|
+
for (const nodeId of allSectionNodeIds) {
|
|
4161
|
+
for (const segmentPointId of segmentPointsInNode.get(nodeId)) {
|
|
4162
|
+
const point = largeSpMaps.segmentPointMap.get(segmentPointId);
|
|
4163
|
+
sectionPointMap.set(segmentPointId, point);
|
|
4033
4164
|
}
|
|
4034
4165
|
}
|
|
4166
|
+
const segmentPoints = Array.from(sectionPointMap.values());
|
|
4035
4167
|
const segmentPointsInSegment = /* @__PURE__ */ new Map();
|
|
4036
4168
|
for (const segmentPoint of segmentPoints) {
|
|
4037
4169
|
segmentPointsInSegment.set(segmentPoint.segmentId, [
|
|
@@ -4041,9 +4173,9 @@ var UnravelSectionSolver = class extends BaseSolver {
|
|
|
4041
4173
|
}
|
|
4042
4174
|
for (const [nodeId, segmentPoints2] of segmentPointsInNode.entries()) {
|
|
4043
4175
|
for (let i = 0; i < segmentPoints2.length; i++) {
|
|
4044
|
-
const A = segmentPointMap.get(segmentPoints2[i]);
|
|
4176
|
+
const A = largeSpMaps.segmentPointMap.get(segmentPoints2[i]);
|
|
4045
4177
|
for (let j = i + 1; j < segmentPoints2.length; j++) {
|
|
4046
|
-
const B = segmentPointMap.get(segmentPoints2[j]);
|
|
4178
|
+
const B = largeSpMaps.segmentPointMap.get(segmentPoints2[j]);
|
|
4047
4179
|
if (B.segmentPointId === A.segmentPointId) continue;
|
|
4048
4180
|
if (B.segmentId === A.segmentId) continue;
|
|
4049
4181
|
if (B.connectionName !== A.connectionName) continue;
|
|
@@ -4055,16 +4187,15 @@ var UnravelSectionSolver = class extends BaseSolver {
|
|
|
4055
4187
|
}
|
|
4056
4188
|
}
|
|
4057
4189
|
const segmentPairsInNode = /* @__PURE__ */ new Map();
|
|
4058
|
-
for (const nodeId of
|
|
4190
|
+
for (const nodeId of allSectionNodeIds) {
|
|
4059
4191
|
segmentPairsInNode.set(nodeId, []);
|
|
4060
4192
|
}
|
|
4061
4193
|
for (const A of segmentPoints) {
|
|
4062
4194
|
for (const nodeId of A.capacityMeshNodeIds) {
|
|
4063
|
-
const otherSegmentPoints = segmentPointsInNode.get(nodeId).map((spId) => segmentPointMap.get(spId));
|
|
4064
4195
|
const segmentPairs = segmentPairsInNode.get(nodeId);
|
|
4065
4196
|
if (!segmentPairs) continue;
|
|
4066
4197
|
for (const BId of A.directlyConnectedSegmentPointIds) {
|
|
4067
|
-
const B = segmentPointMap.get(BId);
|
|
4198
|
+
const B = largeSpMaps.segmentPointMap.get(BId);
|
|
4068
4199
|
if (B.segmentPointId === A.segmentPointId) continue;
|
|
4069
4200
|
if (!B.capacityMeshNodeIds.some((nId) => nId === nodeId)) continue;
|
|
4070
4201
|
if (!segmentPairs.some(
|
|
@@ -4087,14 +4218,15 @@ var UnravelSectionSolver = class extends BaseSolver {
|
|
|
4087
4218
|
}
|
|
4088
4219
|
}
|
|
4089
4220
|
return {
|
|
4090
|
-
allNodeIds,
|
|
4221
|
+
allNodeIds: allSectionNodeIds,
|
|
4091
4222
|
mutableNodeIds,
|
|
4092
4223
|
immutableNodeIds,
|
|
4093
4224
|
mutableSegmentIds,
|
|
4094
4225
|
segmentPairsInNode,
|
|
4095
|
-
segmentPointMap,
|
|
4226
|
+
segmentPointMap: sectionPointMap,
|
|
4096
4227
|
segmentPointsInNode,
|
|
4097
|
-
segmentPointsInSegment
|
|
4228
|
+
segmentPointsInSegment,
|
|
4229
|
+
originalPointMap: sectionPointMap
|
|
4098
4230
|
};
|
|
4099
4231
|
}
|
|
4100
4232
|
createInitialCandidate() {
|
|
@@ -4277,13 +4409,17 @@ var UnravelSectionSolver = class extends BaseSolver {
|
|
|
4277
4409
|
}
|
|
4278
4410
|
return cost;
|
|
4279
4411
|
}
|
|
4280
|
-
|
|
4412
|
+
getUnexploredNeighborByApplyingOperation(currentCandidate, operation) {
|
|
4281
4413
|
const pointModifications = new Map(currentCandidate.pointModifications);
|
|
4282
4414
|
applyOperationToPointModifications(
|
|
4283
4415
|
pointModifications,
|
|
4284
4416
|
operation,
|
|
4285
4417
|
(segmentPointId) => this.getPointInCandidate(currentCandidate, segmentPointId)
|
|
4286
4418
|
);
|
|
4419
|
+
const candidateHash = createPointModificationsHash(pointModifications);
|
|
4420
|
+
if (this.queuedOrExploredCandidatePointModificationHashes.has(candidateHash)) {
|
|
4421
|
+
return null;
|
|
4422
|
+
}
|
|
4287
4423
|
const issues = getIssuesInSection(
|
|
4288
4424
|
this.unravelSection,
|
|
4289
4425
|
this.nodeMap,
|
|
@@ -4302,7 +4438,7 @@ var UnravelSectionSolver = class extends BaseSolver {
|
|
|
4302
4438
|
h: 0,
|
|
4303
4439
|
f: g,
|
|
4304
4440
|
pointModifications,
|
|
4305
|
-
candidateHash
|
|
4441
|
+
candidateHash,
|
|
4306
4442
|
// TODO PERFORMANCE allow disabling this
|
|
4307
4443
|
// candidateFullHash: createFullPointModificationsHash(
|
|
4308
4444
|
// this.unravelSection.segmentPointMap,
|
|
@@ -4320,8 +4456,15 @@ var UnravelSectionSolver = class extends BaseSolver {
|
|
|
4320
4456
|
const neighbors = [];
|
|
4321
4457
|
const operations = this.getNeighborOperationsForCandidate(candidate);
|
|
4322
4458
|
for (const operation of operations) {
|
|
4323
|
-
const neighbor = this.
|
|
4459
|
+
const neighbor = this.getUnexploredNeighborByApplyingOperation(
|
|
4460
|
+
candidate,
|
|
4461
|
+
operation
|
|
4462
|
+
);
|
|
4463
|
+
if (!neighbor) continue;
|
|
4324
4464
|
neighbors.push(neighbor);
|
|
4465
|
+
this.queuedOrExploredCandidatePointModificationHashes.add(
|
|
4466
|
+
neighbor.candidateHash
|
|
4467
|
+
);
|
|
4325
4468
|
}
|
|
4326
4469
|
return neighbors;
|
|
4327
4470
|
}
|
|
@@ -4615,6 +4758,8 @@ var UnravelMultiSectionSolver = class extends BaseSolver {
|
|
|
4615
4758
|
dedupedSegments;
|
|
4616
4759
|
nodeIdToSegmentIds;
|
|
4617
4760
|
segmentIdToNodeIds;
|
|
4761
|
+
nodeToSegmentPointMap;
|
|
4762
|
+
segmentToSegmentPointMap;
|
|
4618
4763
|
colorMap;
|
|
4619
4764
|
tunedNodeCapacityMap;
|
|
4620
4765
|
MAX_NODE_ATTEMPTS = 2;
|
|
@@ -4661,10 +4806,10 @@ var UnravelMultiSectionSolver = class extends BaseSolver {
|
|
|
4661
4806
|
for (const [nodeId, node] of this.nodeMap) {
|
|
4662
4807
|
this.tunedNodeCapacityMap.set(nodeId, getTunedTotalCapacity1(node));
|
|
4663
4808
|
}
|
|
4664
|
-
|
|
4665
|
-
|
|
4666
|
-
|
|
4667
|
-
|
|
4809
|
+
const { segmentPointMap, nodeToSegmentPointMap, segmentToSegmentPointMap } = createSegmentPointMap(this.dedupedSegments, this.segmentIdToNodeIds);
|
|
4810
|
+
this.segmentPointMap = segmentPointMap;
|
|
4811
|
+
this.nodeToSegmentPointMap = nodeToSegmentPointMap;
|
|
4812
|
+
this.segmentToSegmentPointMap = segmentToSegmentPointMap;
|
|
4668
4813
|
this.nodePfMap = this.computeInitialPfMap();
|
|
4669
4814
|
}
|
|
4670
4815
|
computeInitialPfMap() {
|
|
@@ -4680,9 +4825,7 @@ var UnravelMultiSectionSolver = class extends BaseSolver {
|
|
|
4680
4825
|
numEntryExitLayerChanges,
|
|
4681
4826
|
numTransitionCrossings
|
|
4682
4827
|
} = getIntraNodeCrossingsFromSegments(
|
|
4683
|
-
this.
|
|
4684
|
-
(seg) => this.segmentIdToNodeIds.get(seg.nodePortSegmentId).includes(node.capacityMeshNodeId)
|
|
4685
|
-
)
|
|
4828
|
+
this.nodeIdToSegmentIds.get(node.capacityMeshNodeId)?.map((segId) => this.dedupedSegmentMap.get(segId)) || []
|
|
4686
4829
|
);
|
|
4687
4830
|
const probabilityOfFailure = calculateNodeProbabilityOfFailure(
|
|
4688
4831
|
node,
|
|
@@ -4724,7 +4867,9 @@ var UnravelMultiSectionSolver = class extends BaseSolver {
|
|
|
4724
4867
|
colorMap: this.colorMap,
|
|
4725
4868
|
rootNodeId: highestPfNodeId,
|
|
4726
4869
|
MUTABLE_HOPS: this.MUTABLE_HOPS,
|
|
4727
|
-
segmentPointMap: this.segmentPointMap
|
|
4870
|
+
segmentPointMap: this.segmentPointMap,
|
|
4871
|
+
nodeToSegmentPointMap: this.nodeToSegmentPointMap,
|
|
4872
|
+
segmentToSegmentPointMap: this.segmentToSegmentPointMap
|
|
4728
4873
|
});
|
|
4729
4874
|
}
|
|
4730
4875
|
this.activeSolver.step();
|
|
@@ -6066,8 +6211,10 @@ var SegmentTree = class {
|
|
|
6066
6211
|
this.buckets = /* @__PURE__ */ new Map();
|
|
6067
6212
|
for (const segment of segments) {
|
|
6068
6213
|
const bounds = getSegmentBounds(segment);
|
|
6069
|
-
|
|
6070
|
-
|
|
6214
|
+
const bucketMinX = Math.floor(bounds.minX / this.CELL_SIZE) * this.CELL_SIZE;
|
|
6215
|
+
const bucketMinY = Math.floor(bounds.minY / this.CELL_SIZE) * this.CELL_SIZE;
|
|
6216
|
+
for (let x = bucketMinX; x <= bounds.maxX; x += this.CELL_SIZE) {
|
|
6217
|
+
for (let y = bucketMinY; y <= bounds.maxY; y += this.CELL_SIZE) {
|
|
6071
6218
|
const bucketKey = this.getBucketKey(x, y);
|
|
6072
6219
|
const bucket = this.buckets.get(bucketKey);
|
|
6073
6220
|
if (!bucket) {
|
|
@@ -6092,12 +6239,14 @@ var SegmentTree = class {
|
|
|
6092
6239
|
getSegmentsThatCouldIntersect(A, B) {
|
|
6093
6240
|
const segments = [];
|
|
6094
6241
|
const alreadyAddedSegments = /* @__PURE__ */ new Set();
|
|
6095
|
-
const minX = Math.min(A.x, B.x)
|
|
6096
|
-
const minY = Math.min(A.y, B.y)
|
|
6097
|
-
const maxX = Math.max(A.x, B.x)
|
|
6098
|
-
const maxY = Math.max(A.y, B.y)
|
|
6099
|
-
|
|
6100
|
-
|
|
6242
|
+
const minX = Math.min(A.x, B.x);
|
|
6243
|
+
const minY = Math.min(A.y, B.y);
|
|
6244
|
+
const maxX = Math.max(A.x, B.x);
|
|
6245
|
+
const maxY = Math.max(A.y, B.y);
|
|
6246
|
+
const bucketMinX = Math.floor(minX / this.CELL_SIZE) * this.CELL_SIZE;
|
|
6247
|
+
const bucketMinY = Math.floor(minY / this.CELL_SIZE) * this.CELL_SIZE;
|
|
6248
|
+
for (let x = bucketMinX; x <= maxX; x += this.CELL_SIZE) {
|
|
6249
|
+
for (let y = bucketMinY; y <= maxY; y += this.CELL_SIZE) {
|
|
6101
6250
|
const bucketKey = this.getBucketKey(x, y);
|
|
6102
6251
|
const bucket = this.buckets.get(bucketKey) || [];
|
|
6103
6252
|
for (const segment of bucket) {
|