@tscircuit/curvy-trace-solver 0.0.9 → 0.0.10
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 +1 -0
- package/dist/index.js +53 -17
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -39,6 +39,7 @@ declare class CurvyTraceSolver extends BaseSolver {
|
|
|
39
39
|
private collisionPairs;
|
|
40
40
|
private lastCost;
|
|
41
41
|
private stagnantSteps;
|
|
42
|
+
private effectiveTraceToTraceSpacing;
|
|
42
43
|
constructor(problem: CurvyTraceProblem);
|
|
43
44
|
getConstructorParams(): CurvyTraceProblem;
|
|
44
45
|
private precomputeObstacles;
|
package/dist/index.js
CHANGED
|
@@ -1071,6 +1071,8 @@ var CurvyTraceSolver = class extends BaseSolver {
|
|
|
1071
1071
|
collisionPairs = [];
|
|
1072
1072
|
lastCost = Infinity;
|
|
1073
1073
|
stagnantSteps = 0;
|
|
1074
|
+
// Relaxation: start with higher spacing and decay towards actual preferred value
|
|
1075
|
+
effectiveTraceToTraceSpacing = 0;
|
|
1074
1076
|
getConstructorParams() {
|
|
1075
1077
|
return this.problem;
|
|
1076
1078
|
}
|
|
@@ -1227,16 +1229,37 @@ var CurvyTraceSolver = class extends BaseSolver {
|
|
|
1227
1229
|
);
|
|
1228
1230
|
}
|
|
1229
1231
|
// Update control points from perpendicular distances
|
|
1232
|
+
// Ensures control points don't go backwards through the edge the waypoint is on
|
|
1230
1233
|
updateControlPointsFromDistances(i) {
|
|
1231
1234
|
const trace = this.traces[i];
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1235
|
+
const { minX, maxX, minY, maxY } = this.problem.bounds;
|
|
1236
|
+
const eps = 1e-6;
|
|
1237
|
+
let ctrl1x = trace.waypointPair.start.x + trace.d1 * trace.perpDir1.x;
|
|
1238
|
+
let ctrl1y = trace.waypointPair.start.y + trace.d1 * trace.perpDir1.y;
|
|
1239
|
+
let ctrl2x = trace.waypointPair.end.x + trace.d2 * trace.perpDir2.x;
|
|
1240
|
+
let ctrl2y = trace.waypointPair.end.y + trace.d2 * trace.perpDir2.y;
|
|
1241
|
+
const start = trace.waypointPair.start;
|
|
1242
|
+
if (Math.abs(start.x - minX) < eps) ctrl1x = Math.max(ctrl1x, minX);
|
|
1243
|
+
if (Math.abs(start.x - maxX) < eps) ctrl1x = Math.min(ctrl1x, maxX);
|
|
1244
|
+
if (Math.abs(start.y - minY) < eps) ctrl1y = Math.max(ctrl1y, minY);
|
|
1245
|
+
if (Math.abs(start.y - maxY) < eps) ctrl1y = Math.min(ctrl1y, maxY);
|
|
1246
|
+
const end = trace.waypointPair.end;
|
|
1247
|
+
if (Math.abs(end.x - minX) < eps) ctrl2x = Math.max(ctrl2x, minX);
|
|
1248
|
+
if (Math.abs(end.x - maxX) < eps) ctrl2x = Math.min(ctrl2x, maxX);
|
|
1249
|
+
if (Math.abs(end.y - minY) < eps) ctrl2y = Math.max(ctrl2y, minY);
|
|
1250
|
+
if (Math.abs(end.y - maxY) < eps) ctrl2y = Math.min(ctrl2y, maxY);
|
|
1251
|
+
ctrl1x = Math.max(minX, Math.min(maxX, ctrl1x));
|
|
1252
|
+
ctrl1y = Math.max(minY, Math.min(maxY, ctrl1y));
|
|
1253
|
+
ctrl2x = Math.max(minX, Math.min(maxX, ctrl2x));
|
|
1254
|
+
ctrl2y = Math.max(minY, Math.min(maxY, ctrl2y));
|
|
1255
|
+
trace.ctrl1.x = ctrl1x;
|
|
1256
|
+
trace.ctrl1.y = ctrl1y;
|
|
1257
|
+
trace.ctrl2.x = ctrl2x;
|
|
1258
|
+
trace.ctrl2.y = ctrl2y;
|
|
1236
1259
|
}
|
|
1237
1260
|
// Determine which trace pairs could possibly collide based on bounding boxes
|
|
1238
1261
|
updateCollisionPairs() {
|
|
1239
|
-
const
|
|
1262
|
+
const effectiveSpacing = this.effectiveTraceToTraceSpacing;
|
|
1240
1263
|
this.collisionPairs = [];
|
|
1241
1264
|
for (let i = 0; i < this.traces.length; i++) {
|
|
1242
1265
|
for (let j = i + 1; j < this.traces.length; j++) {
|
|
@@ -1244,15 +1267,16 @@ var CurvyTraceSolver = class extends BaseSolver {
|
|
|
1244
1267
|
if (ti.networkId && tj.networkId && ti.networkId === tj.networkId)
|
|
1245
1268
|
continue;
|
|
1246
1269
|
const bi = this.traceBounds[i], bj = this.traceBounds[j];
|
|
1247
|
-
if (bi.maxX +
|
|
1270
|
+
if (bi.maxX + effectiveSpacing >= bj.minX && bj.maxX + effectiveSpacing >= bi.minX && bi.maxY + effectiveSpacing >= bj.minY && bj.maxY + effectiveSpacing >= bi.minY) {
|
|
1248
1271
|
this.collisionPairs.push([i, j]);
|
|
1249
1272
|
}
|
|
1250
1273
|
}
|
|
1251
1274
|
}
|
|
1252
1275
|
}
|
|
1253
1276
|
computeTotalCost() {
|
|
1254
|
-
const {
|
|
1255
|
-
const
|
|
1277
|
+
const { preferredObstacleToTraceSpacing } = this.problem;
|
|
1278
|
+
const effectiveSpacing = this.effectiveTraceToTraceSpacing;
|
|
1279
|
+
const traceSpacingSq = effectiveSpacing ** 2;
|
|
1256
1280
|
const obstacleSpacingSq = preferredObstacleToTraceSpacing ** 2;
|
|
1257
1281
|
let cost = 0;
|
|
1258
1282
|
for (const [i, j] of this.collisionPairs) {
|
|
@@ -1266,7 +1290,7 @@ var CurvyTraceSolver = class extends BaseSolver {
|
|
|
1266
1290
|
const distSq = segmentDistSq(a1x, a1y, a2x, a2y, b1x, b1y, b2x, b2y);
|
|
1267
1291
|
if (distSq < traceSpacingSq) {
|
|
1268
1292
|
const dist = Math.sqrt(distSq);
|
|
1269
|
-
cost += (
|
|
1293
|
+
cost += (effectiveSpacing - dist) ** 2;
|
|
1270
1294
|
if (distSq < 1e-18) cost += 20 * traceSpacingSq;
|
|
1271
1295
|
}
|
|
1272
1296
|
}
|
|
@@ -1303,8 +1327,9 @@ var CurvyTraceSolver = class extends BaseSolver {
|
|
|
1303
1327
|
return cost;
|
|
1304
1328
|
}
|
|
1305
1329
|
computeCostForTrace(traceIdx) {
|
|
1306
|
-
const {
|
|
1307
|
-
const
|
|
1330
|
+
const { preferredObstacleToTraceSpacing } = this.problem;
|
|
1331
|
+
const effectiveSpacing = this.effectiveTraceToTraceSpacing;
|
|
1332
|
+
const traceSpacingSq = effectiveSpacing ** 2;
|
|
1308
1333
|
const obstacleSpacingSq = preferredObstacleToTraceSpacing ** 2;
|
|
1309
1334
|
const trace = this.traces[traceIdx];
|
|
1310
1335
|
const pi = this.sampledPoints[traceIdx];
|
|
@@ -1316,7 +1341,7 @@ var CurvyTraceSolver = class extends BaseSolver {
|
|
|
1316
1341
|
if (trace.networkId && other.networkId && trace.networkId === other.networkId)
|
|
1317
1342
|
continue;
|
|
1318
1343
|
const bj = this.traceBounds[j];
|
|
1319
|
-
if (bi.maxX +
|
|
1344
|
+
if (bi.maxX + effectiveSpacing < bj.minX || bj.maxX + effectiveSpacing < bi.minX || bi.maxY + effectiveSpacing < bj.minY || bj.maxY + effectiveSpacing < bi.minY)
|
|
1320
1345
|
continue;
|
|
1321
1346
|
const pj = this.sampledPoints[j];
|
|
1322
1347
|
for (let a = 0; a < OPT_SAMPLES; a++) {
|
|
@@ -1328,7 +1353,7 @@ var CurvyTraceSolver = class extends BaseSolver {
|
|
|
1328
1353
|
const distSq = segmentDistSq(a1x, a1y, a2x, a2y, b1x, b1y, b2x, b2y);
|
|
1329
1354
|
if (distSq < traceSpacingSq) {
|
|
1330
1355
|
const dist = Math.sqrt(distSq);
|
|
1331
|
-
cost += (
|
|
1356
|
+
cost += (effectiveSpacing - dist) ** 2;
|
|
1332
1357
|
if (distSq < 1e-18) cost += 20 * traceSpacingSq;
|
|
1333
1358
|
}
|
|
1334
1359
|
}
|
|
@@ -1559,9 +1584,10 @@ var CurvyTraceSolver = class extends BaseSolver {
|
|
|
1559
1584
|
return resolved;
|
|
1560
1585
|
}
|
|
1561
1586
|
optimizeStep() {
|
|
1562
|
-
const { bounds
|
|
1587
|
+
const { bounds } = this.problem;
|
|
1563
1588
|
const { minX, maxX, minY, maxY } = bounds;
|
|
1564
1589
|
const minDim = Math.min(maxX - minX, maxY - minY);
|
|
1590
|
+
const effectiveSpacing = this.effectiveTraceToTraceSpacing;
|
|
1565
1591
|
const progress = this.optimizationStep / this.maxOptimizationSteps;
|
|
1566
1592
|
const baseStep = 4 * (1 - progress) + 0.5;
|
|
1567
1593
|
const minDist = minDim * 0.02;
|
|
@@ -1575,7 +1601,11 @@ var CurvyTraceSolver = class extends BaseSolver {
|
|
|
1575
1601
|
if (currentCost === 0) continue;
|
|
1576
1602
|
const trace = this.traces[i];
|
|
1577
1603
|
const costMultiplier = currentCost > 100 ? 2 : 1;
|
|
1578
|
-
const steps = [
|
|
1604
|
+
const steps = [
|
|
1605
|
+
baseStep * costMultiplier,
|
|
1606
|
+
baseStep * 1.5 * costMultiplier,
|
|
1607
|
+
baseStep * 0.5
|
|
1608
|
+
];
|
|
1579
1609
|
for (const step of steps) {
|
|
1580
1610
|
const deltas = currentCost > 100 ? [
|
|
1581
1611
|
step,
|
|
@@ -1584,8 +1614,8 @@ var CurvyTraceSolver = class extends BaseSolver {
|
|
|
1584
1614
|
-step * 2,
|
|
1585
1615
|
step * 3,
|
|
1586
1616
|
-step * 3,
|
|
1587
|
-
|
|
1588
|
-
-
|
|
1617
|
+
effectiveSpacing * 2,
|
|
1618
|
+
-effectiveSpacing * 2
|
|
1589
1619
|
] : [step, -step, step * 2, -step * 2];
|
|
1590
1620
|
let bestCost = this.computeCostForTrace(i);
|
|
1591
1621
|
let bestD1 = trace.d1;
|
|
@@ -1668,11 +1698,17 @@ var CurvyTraceSolver = class extends BaseSolver {
|
|
|
1668
1698
|
}
|
|
1669
1699
|
_step() {
|
|
1670
1700
|
if (this.traces.length === 0) {
|
|
1701
|
+
this.effectiveTraceToTraceSpacing = this.problem.preferredTraceToTraceSpacing * 3;
|
|
1671
1702
|
this.initializeTraces();
|
|
1672
1703
|
this.lastCost = this.computeTotalCost();
|
|
1673
1704
|
this.stagnantSteps = 0;
|
|
1674
1705
|
}
|
|
1675
1706
|
if (this.optimizationStep < this.maxOptimizationSteps) {
|
|
1707
|
+
const progress = this.optimizationStep / this.maxOptimizationSteps;
|
|
1708
|
+
const startMultiplier = 3;
|
|
1709
|
+
const endMultiplier = 1;
|
|
1710
|
+
const currentMultiplier = startMultiplier + (endMultiplier - startMultiplier) * progress;
|
|
1711
|
+
this.effectiveTraceToTraceSpacing = this.problem.preferredTraceToTraceSpacing * currentMultiplier;
|
|
1676
1712
|
this.optimizeStep();
|
|
1677
1713
|
this.optimizationStep++;
|
|
1678
1714
|
if (this.optimizationStep % 10 === 0) {
|