@tscircuit/capacity-autorouter 0.0.3 → 0.0.5
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 +32 -1
- package/dist/index.js +364 -19
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -115,6 +115,11 @@ declare class CapacityMeshNodeSolver extends BaseSolver {
|
|
|
115
115
|
finishedNodes: CapacityMeshNode[];
|
|
116
116
|
nodeToOverlappingObstaclesMap: Map<CapacityMeshNodeId, Obstacle[]>;
|
|
117
117
|
MAX_DEPTH: number;
|
|
118
|
+
targets: Array<{
|
|
119
|
+
x: number;
|
|
120
|
+
y: number;
|
|
121
|
+
connectionName: string;
|
|
122
|
+
}>;
|
|
118
123
|
constructor(srj: SimpleRouteJson, opts?: CapacityMeshNodeSolverOptions);
|
|
119
124
|
_nextNodeCounter: number;
|
|
120
125
|
getNextNodeId(): string;
|
|
@@ -208,6 +213,7 @@ declare class CapacityPathingSolver extends BaseSolver {
|
|
|
208
213
|
reduceCapacityAlongPath(nextConnection: {
|
|
209
214
|
path?: CapacityMeshNode[];
|
|
210
215
|
}): void;
|
|
216
|
+
isConnectedToEndGoal(node: CapacityMeshNode, endGoal: CapacityMeshNode): boolean;
|
|
211
217
|
_step(): void;
|
|
212
218
|
visualize(): GraphicsObject;
|
|
213
219
|
}
|
|
@@ -766,6 +772,30 @@ declare class CapacitySegmentPointOptimizer extends BaseSolver {
|
|
|
766
772
|
visualize(): GraphicsObject;
|
|
767
773
|
}
|
|
768
774
|
|
|
775
|
+
/**
|
|
776
|
+
* Converts a net containing many points to connect into an array of point pair
|
|
777
|
+
* connections.
|
|
778
|
+
*
|
|
779
|
+
* For example, a connection with 3 pointsToConnect could be turned into 2
|
|
780
|
+
* connections of 2 points each.
|
|
781
|
+
*
|
|
782
|
+
* Where we create the minimum number of pairs, we're using a minimum spanning
|
|
783
|
+
* tree (MST).
|
|
784
|
+
*
|
|
785
|
+
* Sometimes it can be used to add additional traces to help make sure we
|
|
786
|
+
* distribute load effectively. In this version we don't do that!
|
|
787
|
+
*/
|
|
788
|
+
declare class NetToPointPairsSolver extends BaseSolver {
|
|
789
|
+
ogSrj: SimpleRouteJson;
|
|
790
|
+
colorMap: Record<string, string>;
|
|
791
|
+
unprocessedConnections: Array<SimpleRouteConnection>;
|
|
792
|
+
newConnections: Array<SimpleRouteConnection>;
|
|
793
|
+
constructor(ogSrj: SimpleRouteJson, colorMap?: Record<string, string>);
|
|
794
|
+
_step(): void;
|
|
795
|
+
getNewSimpleRouteJson(): SimpleRouteJson;
|
|
796
|
+
visualize(): GraphicsObject;
|
|
797
|
+
}
|
|
798
|
+
|
|
769
799
|
interface CapacityMeshSolverOptions {
|
|
770
800
|
capacityDepth?: number;
|
|
771
801
|
targetMinCapacity?: number;
|
|
@@ -773,7 +803,8 @@ interface CapacityMeshSolverOptions {
|
|
|
773
803
|
declare class CapacityMeshSolver extends BaseSolver {
|
|
774
804
|
srj: SimpleRouteJson;
|
|
775
805
|
opts: CapacityMeshSolverOptions;
|
|
776
|
-
|
|
806
|
+
netToPointPairsSolver?: NetToPointPairsSolver;
|
|
807
|
+
nodeSolver?: CapacityMeshNodeSolver;
|
|
777
808
|
nodeTargetMerger?: CapacityNodeTargetMerger;
|
|
778
809
|
edgeSolver?: CapacityMeshEdgeSolver;
|
|
779
810
|
pathingSolver?: CapacityPathingSolver;
|
package/dist/index.js
CHANGED
|
@@ -1092,17 +1092,24 @@ var CapacityMeshNodeSolver = class extends BaseSolver {
|
|
|
1092
1092
|
width: maxWidthHeight,
|
|
1093
1093
|
height: maxWidthHeight,
|
|
1094
1094
|
layer: "top",
|
|
1095
|
-
_depth: 0
|
|
1095
|
+
_depth: 0,
|
|
1096
|
+
_containsTarget: true,
|
|
1097
|
+
_containsObstacle: true,
|
|
1098
|
+
_completelyInsideObstacle: false
|
|
1096
1099
|
}
|
|
1097
1100
|
];
|
|
1098
1101
|
this.finishedNodes = [];
|
|
1099
1102
|
this.nodeToOverlappingObstaclesMap = /* @__PURE__ */ new Map();
|
|
1103
|
+
this.targets = this.srj.connections.flatMap(
|
|
1104
|
+
(c) => c.pointsToConnect.map((p) => ({ ...p, connectionName: c.name }))
|
|
1105
|
+
);
|
|
1100
1106
|
}
|
|
1101
1107
|
unfinishedNodes;
|
|
1102
1108
|
finishedNodes;
|
|
1103
1109
|
nodeToOverlappingObstaclesMap;
|
|
1104
1110
|
// targetObstacleMap: Record<string, { obstacle: Obstacle, node: CapacityMeshNode }>
|
|
1105
1111
|
MAX_DEPTH = 4;
|
|
1112
|
+
targets;
|
|
1106
1113
|
_nextNodeCounter = 0;
|
|
1107
1114
|
getNextNodeId() {
|
|
1108
1115
|
return `cn${this._nextNodeCounter++}`;
|
|
@@ -1112,10 +1119,7 @@ var CapacityMeshNodeSolver = class extends BaseSolver {
|
|
|
1112
1119
|
}
|
|
1113
1120
|
getTargetNameIfNodeContainsTarget(node) {
|
|
1114
1121
|
const overlappingObstacles = this.getOverlappingObstacles(node);
|
|
1115
|
-
const
|
|
1116
|
-
(c) => c.pointsToConnect.map((p) => ({ ...p, connectionName: c.name }))
|
|
1117
|
-
);
|
|
1118
|
-
for (const target of targets) {
|
|
1122
|
+
for (const target of this.targets) {
|
|
1119
1123
|
const targetObstacle = overlappingObstacles.find(
|
|
1120
1124
|
(o) => isPointInRect(target, o)
|
|
1121
1125
|
);
|
|
@@ -1232,9 +1236,9 @@ var CapacityMeshNodeSolver = class extends BaseSolver {
|
|
|
1232
1236
|
_parent: parent
|
|
1233
1237
|
};
|
|
1234
1238
|
childNode._containsObstacle = this.doesNodeOverlapObstacle(childNode);
|
|
1239
|
+
childNode._targetConnectionName = this.getTargetNameIfNodeContainsTarget(childNode) ?? void 0;
|
|
1240
|
+
childNode._containsTarget = Boolean(childNode._targetConnectionName);
|
|
1235
1241
|
if (childNode._containsObstacle) {
|
|
1236
|
-
childNode._targetConnectionName = this.getTargetNameIfNodeContainsTarget(childNode) ?? void 0;
|
|
1237
|
-
childNode._containsTarget = Boolean(childNode._targetConnectionName);
|
|
1238
1242
|
childNode._completelyInsideObstacle = this.isNodeCompletelyInsideObstacle(childNode);
|
|
1239
1243
|
}
|
|
1240
1244
|
if (childNode._completelyInsideObstacle && !childNode._containsTarget)
|
|
@@ -2892,6 +2896,9 @@ var CapacityPathingSolver = class extends BaseSolver {
|
|
|
2892
2896
|
);
|
|
2893
2897
|
}
|
|
2894
2898
|
}
|
|
2899
|
+
isConnectedToEndGoal(node, endGoal) {
|
|
2900
|
+
return this.nodeEdgeMap.get(node.capacityMeshNodeId).some((edge) => edge.nodeIds.includes(endGoal.capacityMeshNodeId));
|
|
2901
|
+
}
|
|
2895
2902
|
_step() {
|
|
2896
2903
|
const nextConnection = this.connectionsWithNodes[this.currentConnectionIndex];
|
|
2897
2904
|
if (!nextConnection) {
|
|
@@ -2918,8 +2925,14 @@ var CapacityPathingSolver = class extends BaseSolver {
|
|
|
2918
2925
|
this.visitedNodes = null;
|
|
2919
2926
|
return;
|
|
2920
2927
|
}
|
|
2921
|
-
if (currentCandidate.node
|
|
2922
|
-
nextConnection.path = this.getBacktrackedPath(
|
|
2928
|
+
if (this.isConnectedToEndGoal(currentCandidate.node, end)) {
|
|
2929
|
+
nextConnection.path = this.getBacktrackedPath({
|
|
2930
|
+
prevCandidate: currentCandidate,
|
|
2931
|
+
node: end,
|
|
2932
|
+
f: 0,
|
|
2933
|
+
g: 0,
|
|
2934
|
+
h: 0
|
|
2935
|
+
});
|
|
2923
2936
|
this.reduceCapacityAlongPath(nextConnection);
|
|
2924
2937
|
this.currentConnectionIndex++;
|
|
2925
2938
|
this.candidates = null;
|
|
@@ -2998,19 +3011,30 @@ ${node.width.toFixed(2)}x${node.height.toFixed(2)}`
|
|
|
2998
3011
|
}
|
|
2999
3012
|
}
|
|
3000
3013
|
}
|
|
3014
|
+
const nextConnection = this.connectionsWithNodes[this.currentConnectionIndex];
|
|
3015
|
+
if (nextConnection) {
|
|
3016
|
+
const [start, end] = nextConnection.connection.pointsToConnect;
|
|
3017
|
+
graphics.lines.push({
|
|
3018
|
+
points: [
|
|
3019
|
+
{ x: start.x, y: start.y },
|
|
3020
|
+
{ x: end.x, y: end.y }
|
|
3021
|
+
],
|
|
3022
|
+
strokeColor: "red",
|
|
3023
|
+
strokeDash: "10 5"
|
|
3024
|
+
});
|
|
3025
|
+
}
|
|
3001
3026
|
if (this.candidates) {
|
|
3002
|
-
const topCandidates = this.candidates.slice(0,
|
|
3027
|
+
const topCandidates = this.candidates.slice(0, 5);
|
|
3003
3028
|
const connectionName = this.connectionsWithNodes[this.currentConnectionIndex].connection.name;
|
|
3004
3029
|
topCandidates.forEach((candidate, index) => {
|
|
3005
|
-
const opacity = 0.
|
|
3030
|
+
const opacity = 0.5 * (1 - index / 5);
|
|
3006
3031
|
const backtrackedPath = this.getBacktrackedPath(candidate);
|
|
3007
3032
|
graphics.lines.push({
|
|
3008
3033
|
points: backtrackedPath.map(({ center: { x, y } }) => ({ x, y })),
|
|
3009
3034
|
strokeColor: safeTransparentize(
|
|
3010
3035
|
this.colorMap[connectionName] ?? "red",
|
|
3011
3036
|
1 - opacity
|
|
3012
|
-
)
|
|
3013
|
-
strokeWidth: 0.5
|
|
3037
|
+
)
|
|
3014
3038
|
});
|
|
3015
3039
|
});
|
|
3016
3040
|
}
|
|
@@ -3960,6 +3984,308 @@ ${segment.nodePortSegmentId}`
|
|
|
3960
3984
|
}
|
|
3961
3985
|
};
|
|
3962
3986
|
|
|
3987
|
+
// lib/solvers/NetToPointPairsSolver/buildMinimumSpanningTree.ts
|
|
3988
|
+
var KDNode = class {
|
|
3989
|
+
point;
|
|
3990
|
+
left = null;
|
|
3991
|
+
right = null;
|
|
3992
|
+
constructor(point) {
|
|
3993
|
+
this.point = point;
|
|
3994
|
+
}
|
|
3995
|
+
};
|
|
3996
|
+
var KDTree = class {
|
|
3997
|
+
root = null;
|
|
3998
|
+
constructor(points) {
|
|
3999
|
+
if (points.length > 0) {
|
|
4000
|
+
this.root = this.buildTree(points, 0);
|
|
4001
|
+
}
|
|
4002
|
+
}
|
|
4003
|
+
buildTree(points, depth) {
|
|
4004
|
+
const axis = depth % 2 === 0 ? "x" : "y";
|
|
4005
|
+
points.sort((a, b) => a[axis] - b[axis]);
|
|
4006
|
+
const medianIndex = Math.floor(points.length / 2);
|
|
4007
|
+
const node = new KDNode(points[medianIndex]);
|
|
4008
|
+
if (medianIndex > 0) {
|
|
4009
|
+
node.left = this.buildTree(points.slice(0, medianIndex), depth + 1);
|
|
4010
|
+
}
|
|
4011
|
+
if (medianIndex < points.length - 1) {
|
|
4012
|
+
node.right = this.buildTree(points.slice(medianIndex + 1), depth + 1);
|
|
4013
|
+
}
|
|
4014
|
+
return node;
|
|
4015
|
+
}
|
|
4016
|
+
// Find the nearest neighbor to a query point
|
|
4017
|
+
findNearestNeighbor(queryPoint) {
|
|
4018
|
+
if (!this.root) {
|
|
4019
|
+
throw new Error("Tree is empty");
|
|
4020
|
+
}
|
|
4021
|
+
const best = this.root.point;
|
|
4022
|
+
const bestDistance = this.distance(queryPoint, best);
|
|
4023
|
+
this.nearestNeighborSearch(this.root, queryPoint, 0, best, bestDistance);
|
|
4024
|
+
return best;
|
|
4025
|
+
}
|
|
4026
|
+
nearestNeighborSearch(node, queryPoint, depth, best, bestDistance) {
|
|
4027
|
+
if (!node) {
|
|
4028
|
+
return best;
|
|
4029
|
+
}
|
|
4030
|
+
const axis = depth % 2 ? "x" : "y";
|
|
4031
|
+
const currentDistance = this.distance(queryPoint, node.point);
|
|
4032
|
+
if (currentDistance < bestDistance) {
|
|
4033
|
+
best = node.point;
|
|
4034
|
+
bestDistance = currentDistance;
|
|
4035
|
+
}
|
|
4036
|
+
const axisDiff = queryPoint[axis] - node.point[axis];
|
|
4037
|
+
const firstBranch = axisDiff <= 0 ? node.left : node.right;
|
|
4038
|
+
const secondBranch = axisDiff <= 0 ? node.right : node.left;
|
|
4039
|
+
best = this.nearestNeighborSearch(
|
|
4040
|
+
firstBranch,
|
|
4041
|
+
queryPoint,
|
|
4042
|
+
depth + 1,
|
|
4043
|
+
best,
|
|
4044
|
+
bestDistance
|
|
4045
|
+
);
|
|
4046
|
+
bestDistance = this.distance(queryPoint, best);
|
|
4047
|
+
if (Math.abs(axisDiff) < bestDistance) {
|
|
4048
|
+
best = this.nearestNeighborSearch(
|
|
4049
|
+
secondBranch,
|
|
4050
|
+
queryPoint,
|
|
4051
|
+
depth + 1,
|
|
4052
|
+
best,
|
|
4053
|
+
bestDistance
|
|
4054
|
+
);
|
|
4055
|
+
}
|
|
4056
|
+
return best;
|
|
4057
|
+
}
|
|
4058
|
+
// Find k nearest neighbors
|
|
4059
|
+
findKNearestNeighbors(queryPoint, k) {
|
|
4060
|
+
if (!this.root) {
|
|
4061
|
+
return [];
|
|
4062
|
+
}
|
|
4063
|
+
const neighbors = [];
|
|
4064
|
+
this.kNearestNeighborSearch(this.root, queryPoint, 0, neighbors, k);
|
|
4065
|
+
return neighbors.sort((a, b) => a.distance - b.distance).slice(0, k).map((n) => n.point);
|
|
4066
|
+
}
|
|
4067
|
+
kNearestNeighborSearch(node, queryPoint, depth, neighbors, k) {
|
|
4068
|
+
if (!node) {
|
|
4069
|
+
return;
|
|
4070
|
+
}
|
|
4071
|
+
const axis = depth % 2 ? "x" : "y";
|
|
4072
|
+
const currentDistance = this.distance(queryPoint, node.point);
|
|
4073
|
+
neighbors.push({ point: node.point, distance: currentDistance });
|
|
4074
|
+
const axisDiff = queryPoint[axis] - node.point[axis];
|
|
4075
|
+
const firstBranch = axisDiff <= 0 ? node.left : node.right;
|
|
4076
|
+
const secondBranch = axisDiff <= 0 ? node.right : node.left;
|
|
4077
|
+
this.kNearestNeighborSearch(
|
|
4078
|
+
firstBranch,
|
|
4079
|
+
queryPoint,
|
|
4080
|
+
depth + 1,
|
|
4081
|
+
neighbors,
|
|
4082
|
+
k
|
|
4083
|
+
);
|
|
4084
|
+
let kthDistance = Infinity;
|
|
4085
|
+
if (neighbors.length >= k) {
|
|
4086
|
+
neighbors.sort((a, b) => a.distance - b.distance);
|
|
4087
|
+
kthDistance = neighbors[k - 1]?.distance || Infinity;
|
|
4088
|
+
}
|
|
4089
|
+
if (Math.abs(axisDiff) < kthDistance || neighbors.length < k) {
|
|
4090
|
+
this.kNearestNeighborSearch(
|
|
4091
|
+
secondBranch,
|
|
4092
|
+
queryPoint,
|
|
4093
|
+
depth + 1,
|
|
4094
|
+
neighbors,
|
|
4095
|
+
k
|
|
4096
|
+
);
|
|
4097
|
+
}
|
|
4098
|
+
}
|
|
4099
|
+
// Calculate Euclidean distance between two points
|
|
4100
|
+
distance(a, b) {
|
|
4101
|
+
return Math.sqrt((a.x - b.x) ** 2 + (a.y - b.y) ** 2);
|
|
4102
|
+
}
|
|
4103
|
+
};
|
|
4104
|
+
var DisjointSet = class {
|
|
4105
|
+
parent = /* @__PURE__ */ new Map();
|
|
4106
|
+
rank = /* @__PURE__ */ new Map();
|
|
4107
|
+
constructor(points) {
|
|
4108
|
+
for (const point of points) {
|
|
4109
|
+
const key = this.pointToKey(point);
|
|
4110
|
+
this.parent.set(key, key);
|
|
4111
|
+
this.rank.set(key, 0);
|
|
4112
|
+
}
|
|
4113
|
+
}
|
|
4114
|
+
pointToKey(point) {
|
|
4115
|
+
return `${point.x},${point.y}`;
|
|
4116
|
+
}
|
|
4117
|
+
find(point) {
|
|
4118
|
+
const key = this.pointToKey(point);
|
|
4119
|
+
if (!this.parent.has(key)) {
|
|
4120
|
+
throw new Error(`Point ${key} not found in DisjointSet`);
|
|
4121
|
+
}
|
|
4122
|
+
let root = key;
|
|
4123
|
+
while (root !== this.parent.get(root)) {
|
|
4124
|
+
root = this.parent.get(root);
|
|
4125
|
+
}
|
|
4126
|
+
let current = key;
|
|
4127
|
+
while (current !== root) {
|
|
4128
|
+
const next = this.parent.get(current);
|
|
4129
|
+
this.parent.set(current, root);
|
|
4130
|
+
current = next;
|
|
4131
|
+
}
|
|
4132
|
+
return root;
|
|
4133
|
+
}
|
|
4134
|
+
union(pointA, pointB) {
|
|
4135
|
+
const rootA = this.find(pointA);
|
|
4136
|
+
const rootB = this.find(pointB);
|
|
4137
|
+
if (rootA === rootB) {
|
|
4138
|
+
return false;
|
|
4139
|
+
}
|
|
4140
|
+
const rankA = this.rank.get(rootA) || 0;
|
|
4141
|
+
const rankB = this.rank.get(rootB) || 0;
|
|
4142
|
+
if (rankA < rankB) {
|
|
4143
|
+
this.parent.set(rootA, rootB);
|
|
4144
|
+
} else if (rankA > rankB) {
|
|
4145
|
+
this.parent.set(rootB, rootA);
|
|
4146
|
+
} else {
|
|
4147
|
+
this.parent.set(rootB, rootA);
|
|
4148
|
+
this.rank.set(rootA, rankA + 1);
|
|
4149
|
+
}
|
|
4150
|
+
return true;
|
|
4151
|
+
}
|
|
4152
|
+
};
|
|
4153
|
+
function buildMinimumSpanningTree(points) {
|
|
4154
|
+
if (points.length <= 1) {
|
|
4155
|
+
return [];
|
|
4156
|
+
}
|
|
4157
|
+
const kdTree = new KDTree(points);
|
|
4158
|
+
const edges = [];
|
|
4159
|
+
const k = Math.min(10, points.length - 1);
|
|
4160
|
+
for (const point of points) {
|
|
4161
|
+
const neighbors = kdTree.findKNearestNeighbors(point, k + 1);
|
|
4162
|
+
for (const neighbor of neighbors) {
|
|
4163
|
+
if (point.x === neighbor.x && point.y === neighbor.y) {
|
|
4164
|
+
continue;
|
|
4165
|
+
}
|
|
4166
|
+
const distance3 = Math.sqrt(
|
|
4167
|
+
(point.x - neighbor.x) ** 2 + (point.y - neighbor.y) ** 2
|
|
4168
|
+
);
|
|
4169
|
+
edges.push({
|
|
4170
|
+
from: point,
|
|
4171
|
+
to: neighbor,
|
|
4172
|
+
weight: distance3
|
|
4173
|
+
});
|
|
4174
|
+
}
|
|
4175
|
+
}
|
|
4176
|
+
edges.sort((a, b) => a.weight - b.weight);
|
|
4177
|
+
const disjointSet = new DisjointSet(points);
|
|
4178
|
+
const mstEdges = [];
|
|
4179
|
+
for (const edge of edges) {
|
|
4180
|
+
if (disjointSet.union(edge.from, edge.to)) {
|
|
4181
|
+
mstEdges.push(edge);
|
|
4182
|
+
if (mstEdges.length === points.length - 1) {
|
|
4183
|
+
break;
|
|
4184
|
+
}
|
|
4185
|
+
}
|
|
4186
|
+
}
|
|
4187
|
+
return mstEdges;
|
|
4188
|
+
}
|
|
4189
|
+
|
|
4190
|
+
// lib/solvers/NetToPointPairsSolver/NetToPointPairsSolver.ts
|
|
4191
|
+
var NetToPointPairsSolver = class extends BaseSolver {
|
|
4192
|
+
constructor(ogSrj, colorMap = {}) {
|
|
4193
|
+
super();
|
|
4194
|
+
this.ogSrj = ogSrj;
|
|
4195
|
+
this.colorMap = colorMap;
|
|
4196
|
+
this.unprocessedConnections = ogSrj.connections;
|
|
4197
|
+
this.newConnections = [];
|
|
4198
|
+
}
|
|
4199
|
+
unprocessedConnections;
|
|
4200
|
+
newConnections;
|
|
4201
|
+
_step() {
|
|
4202
|
+
if (this.unprocessedConnections.length === 0) {
|
|
4203
|
+
this.solved = true;
|
|
4204
|
+
return;
|
|
4205
|
+
}
|
|
4206
|
+
const connection = this.unprocessedConnections.pop();
|
|
4207
|
+
if (connection.pointsToConnect.length === 2) {
|
|
4208
|
+
this.newConnections.push(connection);
|
|
4209
|
+
return;
|
|
4210
|
+
}
|
|
4211
|
+
const edges = buildMinimumSpanningTree(connection.pointsToConnect);
|
|
4212
|
+
for (const edge of edges) {
|
|
4213
|
+
this.newConnections.push({
|
|
4214
|
+
pointsToConnect: [edge.from, edge.to],
|
|
4215
|
+
name: connection.name
|
|
4216
|
+
});
|
|
4217
|
+
}
|
|
4218
|
+
}
|
|
4219
|
+
getNewSimpleRouteJson() {
|
|
4220
|
+
return {
|
|
4221
|
+
...this.ogSrj,
|
|
4222
|
+
connections: this.newConnections
|
|
4223
|
+
};
|
|
4224
|
+
}
|
|
4225
|
+
visualize() {
|
|
4226
|
+
const graphics = {
|
|
4227
|
+
lines: [],
|
|
4228
|
+
points: [],
|
|
4229
|
+
rects: [],
|
|
4230
|
+
circles: [],
|
|
4231
|
+
coordinateSystem: "cartesian",
|
|
4232
|
+
title: "Net To Point Pairs Visualization"
|
|
4233
|
+
};
|
|
4234
|
+
this.unprocessedConnections.forEach((connection) => {
|
|
4235
|
+
connection.pointsToConnect.forEach((point) => {
|
|
4236
|
+
graphics.points.push({
|
|
4237
|
+
x: point.x,
|
|
4238
|
+
y: point.y,
|
|
4239
|
+
color: "red",
|
|
4240
|
+
label: connection.name
|
|
4241
|
+
});
|
|
4242
|
+
});
|
|
4243
|
+
const fullyConnectedEdgeCount = connection.pointsToConnect.length ** 2;
|
|
4244
|
+
const random = seededRandom(0);
|
|
4245
|
+
const alreadyPlacedEdges = /* @__PURE__ */ new Set();
|
|
4246
|
+
for (let i = 0; i < Math.max(
|
|
4247
|
+
fullyConnectedEdgeCount,
|
|
4248
|
+
connection.pointsToConnect.length * 2
|
|
4249
|
+
); i++) {
|
|
4250
|
+
const a = Math.floor(random() * connection.pointsToConnect.length);
|
|
4251
|
+
const b = Math.floor(random() * connection.pointsToConnect.length);
|
|
4252
|
+
if (alreadyPlacedEdges.has(`${a}-${b}`)) continue;
|
|
4253
|
+
alreadyPlacedEdges.add(`${a}-${b}`);
|
|
4254
|
+
graphics.lines.push({
|
|
4255
|
+
points: [
|
|
4256
|
+
connection.pointsToConnect[a],
|
|
4257
|
+
connection.pointsToConnect[b]
|
|
4258
|
+
],
|
|
4259
|
+
strokeColor: "rgba(255,0,0,0.25)"
|
|
4260
|
+
});
|
|
4261
|
+
}
|
|
4262
|
+
});
|
|
4263
|
+
this.newConnections.forEach((connection) => {
|
|
4264
|
+
const color = this.colorMap?.[connection.name] || "blue";
|
|
4265
|
+
connection.pointsToConnect.forEach((point) => {
|
|
4266
|
+
graphics.points.push({
|
|
4267
|
+
x: point.x,
|
|
4268
|
+
y: point.y,
|
|
4269
|
+
color,
|
|
4270
|
+
label: connection.name
|
|
4271
|
+
});
|
|
4272
|
+
});
|
|
4273
|
+
for (let i = 0; i < connection.pointsToConnect.length - 1; i++) {
|
|
4274
|
+
for (let j = i + 1; j < connection.pointsToConnect.length; j++) {
|
|
4275
|
+
graphics.lines.push({
|
|
4276
|
+
points: [
|
|
4277
|
+
connection.pointsToConnect[i],
|
|
4278
|
+
connection.pointsToConnect[j]
|
|
4279
|
+
],
|
|
4280
|
+
strokeColor: color
|
|
4281
|
+
});
|
|
4282
|
+
}
|
|
4283
|
+
}
|
|
4284
|
+
});
|
|
4285
|
+
return graphics;
|
|
4286
|
+
}
|
|
4287
|
+
};
|
|
4288
|
+
|
|
3963
4289
|
// lib/solvers/CapacityMeshSolver/CapacityMeshSolver.ts
|
|
3964
4290
|
var CapacityMeshSolver = class extends BaseSolver {
|
|
3965
4291
|
constructor(srj, opts = {}) {
|
|
@@ -3977,10 +4303,10 @@ var CapacityMeshSolver = class extends BaseSolver {
|
|
|
3977
4303
|
targetMinCapacity
|
|
3978
4304
|
);
|
|
3979
4305
|
}
|
|
3980
|
-
this.nodeSolver = new CapacityMeshNodeSolver(srj, this.opts);
|
|
3981
4306
|
this.connMap = getConnectivityMapFromSimpleRouteJson(srj);
|
|
3982
4307
|
this.colorMap = getColorMap(srj, this.connMap);
|
|
3983
4308
|
}
|
|
4309
|
+
netToPointPairsSolver;
|
|
3984
4310
|
nodeSolver;
|
|
3985
4311
|
nodeTargetMerger;
|
|
3986
4312
|
edgeSolver;
|
|
@@ -4004,7 +4330,19 @@ var CapacityMeshSolver = class extends BaseSolver {
|
|
|
4004
4330
|
}
|
|
4005
4331
|
return;
|
|
4006
4332
|
}
|
|
4007
|
-
if (!this.
|
|
4333
|
+
if (!this.netToPointPairsSolver) {
|
|
4334
|
+
this.netToPointPairsSolver = new NetToPointPairsSolver(
|
|
4335
|
+
this.srj,
|
|
4336
|
+
this.colorMap
|
|
4337
|
+
);
|
|
4338
|
+
this.activeSolver = this.netToPointPairsSolver;
|
|
4339
|
+
return;
|
|
4340
|
+
}
|
|
4341
|
+
if (!this.nodeSolver) {
|
|
4342
|
+
this.nodeSolver = new CapacityMeshNodeSolver(
|
|
4343
|
+
this.netToPointPairsSolver.getNewSimpleRouteJson(),
|
|
4344
|
+
this.opts
|
|
4345
|
+
);
|
|
4008
4346
|
this.activeSolver = this.nodeSolver;
|
|
4009
4347
|
return;
|
|
4010
4348
|
}
|
|
@@ -4025,7 +4363,7 @@ var CapacityMeshSolver = class extends BaseSolver {
|
|
|
4025
4363
|
}
|
|
4026
4364
|
if (!this.pathingSolver) {
|
|
4027
4365
|
this.pathingSolver = new CapacityPathingSolver4_FlexibleNegativeCapacity({
|
|
4028
|
-
simpleRouteJson: this.
|
|
4366
|
+
simpleRouteJson: this.netToPointPairsSolver.getNewSimpleRouteJson(),
|
|
4029
4367
|
nodes,
|
|
4030
4368
|
edges: this.edgeSolver.edges,
|
|
4031
4369
|
colorMap: this.colorMap,
|
|
@@ -4082,7 +4420,8 @@ var CapacityMeshSolver = class extends BaseSolver {
|
|
|
4082
4420
|
}
|
|
4083
4421
|
visualize() {
|
|
4084
4422
|
if (!this.solved && this.activeSolver) return this.activeSolver.visualize();
|
|
4085
|
-
const
|
|
4423
|
+
const netToPPSolver = this.netToPointPairsSolver?.visualize();
|
|
4424
|
+
const nodeViz = this.nodeSolver?.visualize();
|
|
4086
4425
|
const edgeViz = this.edgeSolver?.visualize();
|
|
4087
4426
|
const pathingViz = this.pathingSolver?.visualize();
|
|
4088
4427
|
const edgeToPortSegmentViz = this.edgeToPortSegmentSolver?.visualize();
|
|
@@ -4090,11 +4429,17 @@ var CapacityMeshSolver = class extends BaseSolver {
|
|
|
4090
4429
|
const segmentOptimizationViz = this.segmentToPointOptimizer?.visualize();
|
|
4091
4430
|
const highDensityViz = this.highDensityRouteSolver?.visualize();
|
|
4092
4431
|
const problemViz = {
|
|
4093
|
-
points: [...
|
|
4094
|
-
rects: [
|
|
4432
|
+
points: [...this.srj.connections.flatMap((c) => c.pointsToConnect)],
|
|
4433
|
+
rects: [
|
|
4434
|
+
...(this.srj.obstacles ?? []).map((o) => ({
|
|
4435
|
+
...o,
|
|
4436
|
+
fill: "rgba(255,0,0,0.25)"
|
|
4437
|
+
}))
|
|
4438
|
+
]
|
|
4095
4439
|
};
|
|
4096
4440
|
const visualizations = [
|
|
4097
4441
|
problemViz,
|
|
4442
|
+
netToPPSolver,
|
|
4098
4443
|
nodeViz,
|
|
4099
4444
|
edgeViz,
|
|
4100
4445
|
pathingViz,
|