@tscircuit/curvy-trace-solver 0.0.8 → 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 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
- trace.ctrl1.x = trace.waypointPair.start.x + trace.d1 * trace.perpDir1.x;
1233
- trace.ctrl1.y = trace.waypointPair.start.y + trace.d1 * trace.perpDir1.y;
1234
- trace.ctrl2.x = trace.waypointPair.end.x + trace.d2 * trace.perpDir2.x;
1235
- trace.ctrl2.y = trace.waypointPair.end.y + trace.d2 * trace.perpDir2.y;
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 { preferredTraceToTraceSpacing: preferredSpacing } = this.problem;
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 + preferredSpacing >= bj.minX && bj.maxX + preferredSpacing >= bi.minX && bi.maxY + preferredSpacing >= bj.minY && bj.maxY + preferredSpacing >= bi.minY) {
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 { preferredTraceToTraceSpacing, preferredObstacleToTraceSpacing } = this.problem;
1255
- const traceSpacingSq = preferredTraceToTraceSpacing ** 2;
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 += (preferredTraceToTraceSpacing - dist) ** 2;
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 { preferredTraceToTraceSpacing, preferredObstacleToTraceSpacing } = this.problem;
1307
- const traceSpacingSq = preferredTraceToTraceSpacing ** 2;
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 + preferredTraceToTraceSpacing < bj.minX || bj.maxX + preferredTraceToTraceSpacing < bi.minX || bi.maxY + preferredTraceToTraceSpacing < bj.minY || bj.maxY + preferredTraceToTraceSpacing < bi.minY)
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 += (preferredTraceToTraceSpacing - dist) ** 2;
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, preferredTraceToTraceSpacing } = this.problem;
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 = [baseStep * costMultiplier, baseStep * 1.5 * costMultiplier, baseStep * 0.5];
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
- preferredTraceToTraceSpacing * 2,
1588
- -preferredTraceToTraceSpacing * 2
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) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tscircuit/curvy-trace-solver",
3
3
  "main": "dist/index.js",
4
- "version": "0.0.8",
4
+ "version": "0.0.10",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "start": "cosmos",