@tscircuit/schematic-trace-solver 0.0.169 → 0.0.170

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.js CHANGED
@@ -325,19 +325,19 @@ var doesPairCrossRestrictedCenterLines = (params) => {
325
325
  chipMap
326
326
  });
327
327
  if (restrictedCenterLines.size === 0) return false;
328
- const EPS14 = 1e-9;
328
+ const EPS15 = 1e-9;
329
329
  const crossesSegment = (a, b) => {
330
330
  for (const [, rcl] of restrictedCenterLines) {
331
331
  if (rcl.axes.has("x") && typeof rcl.x === "number") {
332
- if ((a.x - rcl.x) * (b.x - rcl.x) < -EPS14) return true;
332
+ if ((a.x - rcl.x) * (b.x - rcl.x) < -EPS15) return true;
333
333
  }
334
334
  if (rcl.axes.has("y") && typeof rcl.y === "number") {
335
- if ((a.y - rcl.y) * (b.y - rcl.y) < -EPS14) return true;
335
+ if ((a.y - rcl.y) * (b.y - rcl.y) < -EPS15) return true;
336
336
  }
337
337
  }
338
338
  return false;
339
339
  };
340
- if (Math.abs(p1.x - p2.x) < EPS14 || Math.abs(p1.y - p2.y) < EPS14) {
340
+ if (Math.abs(p1.x - p2.x) < EPS15 || Math.abs(p1.y - p2.y) < EPS15) {
341
341
  return crossesSegment({ x: p1.x, y: p1.y }, { x: p2.x, y: p2.y });
342
342
  }
343
343
  const elbowHV = { x: p2.x, y: p1.y };
@@ -1575,8 +1575,8 @@ var SchematicTraceSingleLineSolver2 = class extends BaseSolver {
1575
1575
  if (!collision) {
1576
1576
  const first = path[0];
1577
1577
  const last = path[path.length - 1];
1578
- const EPS14 = 1e-9;
1579
- const samePoint = (p, q) => Math.abs(p.x - q.x) < EPS14 && Math.abs(p.y - q.y) < EPS14;
1578
+ const EPS15 = 1e-9;
1579
+ const samePoint = (p, q) => Math.abs(p.x - q.x) < EPS15 && Math.abs(p.y - q.y) < EPS15;
1580
1580
  if (samePoint(first, { x: PA.x, y: PA.y }) && samePoint(last, { x: PB.x, y: PB.y })) {
1581
1581
  this.solvedTracePath = path;
1582
1582
  this.solved = true;
@@ -1887,17 +1887,17 @@ var applyJogToTerminalSegment = ({
1887
1887
  segmentIndex: si,
1888
1888
  offset,
1889
1889
  JOG_SIZE,
1890
- EPS: EPS14 = 1e-6
1890
+ EPS: EPS15 = 1e-6
1891
1891
  }) => {
1892
1892
  if (si !== 0 && si !== pts.length - 2) return;
1893
1893
  const start = pts[si];
1894
1894
  const end = pts[si + 1];
1895
- const isVertical5 = Math.abs(start.x - end.x) < EPS14;
1896
- const isHorizontal4 = Math.abs(start.y - end.y) < EPS14;
1897
- if (!isVertical5 && !isHorizontal4) return;
1898
- const segDir = isVertical5 ? end.y > start.y ? 1 : -1 : end.x > start.x ? 1 : -1;
1895
+ const isVertical6 = Math.abs(start.x - end.x) < EPS15;
1896
+ const isHorizontal5 = Math.abs(start.y - end.y) < EPS15;
1897
+ if (!isVertical6 && !isHorizontal5) return;
1898
+ const segDir = isVertical6 ? end.y > start.y ? 1 : -1 : end.x > start.x ? 1 : -1;
1899
1899
  if (pts.length === 2) {
1900
- if (isVertical5) {
1900
+ if (isVertical6) {
1901
1901
  const jogYNearStart = start.y + segDir * JOG_SIZE;
1902
1902
  const jogYNearEnd = end.y - segDir * JOG_SIZE;
1903
1903
  pts.splice(
@@ -1923,7 +1923,7 @@ var applyJogToTerminalSegment = ({
1923
1923
  return;
1924
1924
  }
1925
1925
  if (si === 0) {
1926
- if (isVertical5) {
1926
+ if (isVertical6) {
1927
1927
  const jogY = start.y + segDir * JOG_SIZE;
1928
1928
  pts.splice(
1929
1929
  1,
@@ -1943,7 +1943,7 @@ var applyJogToTerminalSegment = ({
1943
1943
  );
1944
1944
  }
1945
1945
  } else {
1946
- if (isVertical5) {
1946
+ if (isVertical6) {
1947
1947
  const jogY = end.y - segDir * JOG_SIZE;
1948
1948
  pts.splice(
1949
1949
  si,
@@ -2175,11 +2175,11 @@ var TraceOverlapIssueSolver = class extends BaseSolver {
2175
2175
  }) {
2176
2176
  const blockingCollisions = this.getBlockingCollisions({ group, offset });
2177
2177
  if (blockingCollisions.length === 0) return offset;
2178
- const crossesThroughObstacle = (candidateOffset) => blockingCollisions.some(({ start, isVertical: isVertical5, obstacle }) => {
2178
+ const crossesThroughObstacle = (candidateOffset) => blockingCollisions.some(({ start, isVertical: isVertical6, obstacle }) => {
2179
2179
  let orig;
2180
2180
  let min;
2181
2181
  let max;
2182
- if (isVertical5) {
2182
+ if (isVertical6) {
2183
2183
  orig = start.x;
2184
2184
  min = obstacle.minX;
2185
2185
  max = obstacle.maxX;
@@ -2191,8 +2191,8 @@ var TraceOverlapIssueSolver = class extends BaseSolver {
2191
2191
  const next = orig + candidateOffset;
2192
2192
  return orig <= min + EPS5 && next >= max - EPS5 || orig >= max - EPS5 && next <= min + EPS5;
2193
2193
  });
2194
- const edges = blockingCollisions.map(({ start, isVertical: isVertical5, obstacle }) => {
2195
- if (isVertical5) {
2194
+ const edges = blockingCollisions.map(({ start, isVertical: isVertical6, obstacle }) => {
2195
+ if (isVertical6) {
2196
2196
  return {
2197
2197
  coord: start.x,
2198
2198
  lowEdge: obstacle.minX,
@@ -2226,10 +2226,10 @@ var TraceOverlapIssueSolver = class extends BaseSolver {
2226
2226
  const start = trace.tracePath[traceSegmentIndex];
2227
2227
  const end = trace.tracePath[traceSegmentIndex + 1];
2228
2228
  if (!start || !end) continue;
2229
- const isVertical5 = Math.abs(start.x - end.x) < EPS5;
2230
- const isHorizontal4 = Math.abs(start.y - end.y) < EPS5;
2231
- if (!isVertical5 && !isHorizontal4) continue;
2232
- const shiftedSegment = isVertical5 ? [
2229
+ const isVertical6 = Math.abs(start.x - end.x) < EPS5;
2230
+ const isHorizontal5 = Math.abs(start.y - end.y) < EPS5;
2231
+ if (!isVertical6 && !isHorizontal5) continue;
2232
+ const shiftedSegment = isVertical6 ? [
2233
2233
  { ...start, x: start.x + offset },
2234
2234
  { ...end, x: end.x + offset }
2235
2235
  ] : [
@@ -2240,7 +2240,7 @@ var TraceOverlapIssueSolver = class extends BaseSolver {
2240
2240
  if (collision) {
2241
2241
  blockingCollisions.push({
2242
2242
  start,
2243
- isVertical: isVertical5,
2243
+ isVertical: isVertical6,
2244
2244
  obstacle: collision.rect
2245
2245
  });
2246
2246
  }
@@ -2327,7 +2327,7 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
2327
2327
  return islands;
2328
2328
  }
2329
2329
  findNextOverlapIssue() {
2330
- const EPS14 = 2e-3;
2330
+ const EPS15 = 2e-3;
2331
2331
  const netIds = Object.keys(this.traceNetIslands);
2332
2332
  for (let i = 0; i < netIds.length; i++) {
2333
2333
  for (let j = i + 1; j < netIds.length; j++) {
@@ -2354,7 +2354,7 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
2354
2354
  segmentBIndex,
2355
2355
  rangeOverlap
2356
2356
  }) => {
2357
- if (rangeOverlap > EPS14) {
2357
+ if (rangeOverlap > EPS15) {
2358
2358
  const keyA = `${pathAIndex}:${segmentAIndex}`;
2359
2359
  const keyB = `${pathBIndex}:${segmentBIndex}`;
2360
2360
  if (!seenA.has(keyA)) {
@@ -2373,7 +2373,7 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
2373
2373
  }
2374
2374
  return;
2375
2375
  }
2376
- if (rangeOverlap < -EPS14) return;
2376
+ if (rangeOverlap < -EPS15) return;
2377
2377
  const pathA = pathsA[pathAIndex].tracePath;
2378
2378
  const pathB = pathsB[pathBIndex].tracePath;
2379
2379
  const segmentAStart = pathA[segmentAIndex];
@@ -2396,8 +2396,8 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
2396
2396
  for (let sa = 0; sa < ptsA.length - 1; sa++) {
2397
2397
  const a1 = ptsA[sa];
2398
2398
  const a2 = ptsA[sa + 1];
2399
- const aVert = Math.abs(a1.x - a2.x) < EPS14;
2400
- const aHorz = Math.abs(a1.y - a2.y) < EPS14;
2399
+ const aVert = Math.abs(a1.x - a2.x) < EPS15;
2400
+ const aHorz = Math.abs(a1.y - a2.y) < EPS15;
2401
2401
  if (!aVert && !aHorz) continue;
2402
2402
  for (let pb = 0; pb < pathsB.length; pb++) {
2403
2403
  const pathB = pathsB[pb];
@@ -2408,11 +2408,11 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
2408
2408
  for (let sb = 0; sb < ptsB.length - 1; sb++) {
2409
2409
  const b1 = ptsB[sb];
2410
2410
  const b2 = ptsB[sb + 1];
2411
- const bVert = Math.abs(b1.x - b2.x) < EPS14;
2412
- const bHorz = Math.abs(b1.y - b2.y) < EPS14;
2411
+ const bVert = Math.abs(b1.x - b2.x) < EPS15;
2412
+ const bHorz = Math.abs(b1.y - b2.y) < EPS15;
2413
2413
  if (!bVert && !bHorz) continue;
2414
2414
  if (aVert && bVert) {
2415
- if (Math.abs(a1.x - b1.x) < EPS14) {
2415
+ if (Math.abs(a1.x - b1.x) < EPS15) {
2416
2416
  recordCollinearInteraction({
2417
2417
  pathAIndex: pa,
2418
2418
  segmentAIndex: sa,
@@ -2422,7 +2422,7 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
2422
2422
  });
2423
2423
  }
2424
2424
  } else if (aHorz && bHorz) {
2425
- if (Math.abs(a1.y - b1.y) < EPS14) {
2425
+ if (Math.abs(a1.y - b1.y) < EPS15) {
2426
2426
  recordCollinearInteraction({
2427
2427
  pathAIndex: pa,
2428
2428
  segmentAIndex: sa,
@@ -2478,15 +2478,15 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
2478
2478
  return null;
2479
2479
  }
2480
2480
  findNextDiagonalSegment() {
2481
- const EPS14 = 2e-3;
2481
+ const EPS15 = 2e-3;
2482
2482
  for (const mspPairId in this.correctedTraceMap) {
2483
2483
  const tracePath = this.correctedTraceMap[mspPairId].tracePath;
2484
2484
  for (let i = 0; i < tracePath.length - 1; i++) {
2485
2485
  const p1 = tracePath[i];
2486
2486
  const p2 = tracePath[i + 1];
2487
- const isHorizontal4 = Math.abs(p1.y - p2.y) < EPS14;
2488
- const isVertical5 = Math.abs(p1.x - p2.x) < EPS14;
2489
- if (!isHorizontal4 && !isVertical5) {
2487
+ const isHorizontal5 = Math.abs(p1.y - p2.y) < EPS15;
2488
+ const isVertical6 = Math.abs(p1.x - p2.x) < EPS15;
2489
+ if (!isHorizontal5 && !isVertical6) {
2490
2490
  return { mspPairId, tracePath, i, p1, p2 };
2491
2491
  }
2492
2492
  }
@@ -2499,13 +2499,13 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
2499
2499
  return false;
2500
2500
  }
2501
2501
  const { mspPairId, tracePath, i, p1, p2 } = diagonalInfo;
2502
- const EPS14 = 2e-3;
2502
+ const EPS15 = 2e-3;
2503
2503
  const p0 = i > 0 ? tracePath[i - 1] : null;
2504
2504
  const p3 = i + 2 < tracePath.length ? tracePath[i + 2] : null;
2505
- const prevIsVertical = p0 ? Math.abs(p0.x - p1.x) < EPS14 : false;
2506
- const prevIsHorizontal = p0 ? Math.abs(p0.y - p1.y) < EPS14 : false;
2507
- const nextIsVertical = p3 ? Math.abs(p2.x - p3.x) < EPS14 : false;
2508
- const nextIsHorizontal = p3 ? Math.abs(p2.y - p3.y) < EPS14 : false;
2505
+ const prevIsVertical = p0 ? Math.abs(p0.x - p1.x) < EPS15 : false;
2506
+ const prevIsHorizontal = p0 ? Math.abs(p0.y - p1.y) < EPS15 : false;
2507
+ const nextIsVertical = p3 ? Math.abs(p2.x - p3.x) < EPS15 : false;
2508
+ const nextIsHorizontal = p3 ? Math.abs(p2.y - p3.y) < EPS15 : false;
2509
2509
  const elbow1 = { x: p1.x, y: p2.y };
2510
2510
  const elbow2 = { x: p2.x, y: p1.y };
2511
2511
  let score1 = 0;
@@ -2667,24 +2667,24 @@ var ChipObstacleSpatialIndex = class {
2667
2667
  };
2668
2668
 
2669
2669
  // lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/collisions.ts
2670
- function segmentIntersectsRect2(p1, p2, rect, EPS14 = 1e-9) {
2671
- const isVert = Math.abs(p1.x - p2.x) < EPS14;
2672
- const isHorz = Math.abs(p1.y - p2.y) < EPS14;
2670
+ function segmentIntersectsRect2(p1, p2, rect, EPS15 = 1e-9) {
2671
+ const isVert = Math.abs(p1.x - p2.x) < EPS15;
2672
+ const isHorz = Math.abs(p1.y - p2.y) < EPS15;
2673
2673
  if (!isVert && !isHorz) return false;
2674
2674
  if (isVert) {
2675
2675
  const x = p1.x;
2676
- if (x < rect.minX - EPS14 || x > rect.maxX + EPS14) return false;
2676
+ if (x < rect.minX - EPS15 || x > rect.maxX + EPS15) return false;
2677
2677
  const segMinY = Math.min(p1.y, p2.y);
2678
2678
  const segMaxY = Math.max(p1.y, p2.y);
2679
2679
  const overlap = Math.min(segMaxY, rect.maxY) - Math.max(segMinY, rect.minY);
2680
- return overlap > EPS14;
2680
+ return overlap > EPS15;
2681
2681
  } else {
2682
2682
  const y = p1.y;
2683
- if (y < rect.minY - EPS14 || y > rect.maxY + EPS14) return false;
2683
+ if (y < rect.minY - EPS15 || y > rect.maxY + EPS15) return false;
2684
2684
  const segMinX = Math.min(p1.x, p2.x);
2685
2685
  const segMaxX = Math.max(p1.x, p2.x);
2686
2686
  const overlap = Math.min(segMaxX, rect.maxX) - Math.max(segMinX, rect.minX);
2687
- return overlap > EPS14;
2687
+ return overlap > EPS15;
2688
2688
  }
2689
2689
  }
2690
2690
  function rectIntersectsAnyTrace(bounds, inputTraceMap, hostPathId, hostSegIndex) {
@@ -3083,14 +3083,14 @@ var SingleNetLabelPlacementSolver = class extends BaseSolver {
3083
3083
  };
3084
3084
  let bestCandidate = null;
3085
3085
  let bestScore = -Infinity;
3086
- const EPS14 = 1e-6;
3086
+ const EPS15 = 1e-6;
3087
3087
  for (const curr of tracesToScan) {
3088
3088
  const pts = curr.tracePath.slice();
3089
3089
  for (let si = 0; si < pts.length - 1; si++) {
3090
3090
  const a = pts[si];
3091
3091
  const b = pts[si + 1];
3092
- const isH = Math.abs(a.y - b.y) < EPS14;
3093
- const isV = Math.abs(a.x - b.x) < EPS14;
3092
+ const isH = Math.abs(a.y - b.y) < EPS15;
3093
+ const isV = Math.abs(a.x - b.x) < EPS15;
3094
3094
  if (!isH && !isV) continue;
3095
3095
  const segmentAllowed = isH ? ["y+", "y-"] : ["x+", "x-"];
3096
3096
  const candidateOrients = orientations.filter(
@@ -4176,11 +4176,11 @@ var doesPathCoincideWithTraces = (path, traces) => {
4176
4176
  for (let i = 0; i < path.length - 1; i++) {
4177
4177
  const pathSegStart = path[i];
4178
4178
  const pathSegEnd = path[i + 1];
4179
- const isVertical5 = Math.abs(pathSegStart.x - pathSegEnd.x) < COINCIDENT_EPS;
4180
- const isHorizontal4 = Math.abs(pathSegStart.y - pathSegEnd.y) < COINCIDENT_EPS;
4181
- if (!isVertical5 && !isHorizontal4) continue;
4182
- const crossAxis = isVertical5 ? "x" : "y";
4183
- const alongAxis = isVertical5 ? "y" : "x";
4179
+ const isVertical6 = Math.abs(pathSegStart.x - pathSegEnd.x) < COINCIDENT_EPS;
4180
+ const isHorizontal5 = Math.abs(pathSegStart.y - pathSegEnd.y) < COINCIDENT_EPS;
4181
+ if (!isVertical6 && !isHorizontal5) continue;
4182
+ const crossAxis = isVertical6 ? "x" : "y";
4183
+ const alongAxis = isVertical6 ? "y" : "x";
4184
4184
  for (const trace of traces) {
4185
4185
  for (let j = 0; j < trace.tracePath.length - 1; j++) {
4186
4186
  const traceSegStart = trace.tracePath[j];
@@ -4204,7 +4204,7 @@ var doesPathCoincideWithTraces = (path, traces) => {
4204
4204
  };
4205
4205
  var doesPathOverlapTraceStrokes = (path, traces) => {
4206
4206
  const traceStrokeRadius = SCHEMATIC_TRACE_MIN_CENTERLINE_CLEARANCE / 2;
4207
- const getStrokeBounds = (start, end, isVertical5) => isVertical5 ? {
4207
+ const getStrokeBounds = (start, end, isVertical6) => isVertical6 ? {
4208
4208
  minX: start.x - traceStrokeRadius,
4209
4209
  maxX: start.x + traceStrokeRadius,
4210
4210
  minY: Math.min(start.y, end.y),
@@ -4218,22 +4218,22 @@ var doesPathOverlapTraceStrokes = (path, traces) => {
4218
4218
  for (let pathIndex = 0; pathIndex < path.length - 1; pathIndex++) {
4219
4219
  const pathStart = path[pathIndex];
4220
4220
  const pathEnd = path[pathIndex + 1];
4221
- const isVertical5 = Math.abs(pathStart.x - pathEnd.x) < COINCIDENT_EPS;
4222
- const isHorizontal4 = Math.abs(pathStart.y - pathEnd.y) < COINCIDENT_EPS;
4223
- if (!isVertical5 && !isHorizontal4) continue;
4224
- const pathBounds = getStrokeBounds(pathStart, pathEnd, isVertical5);
4221
+ const isVertical6 = Math.abs(pathStart.x - pathEnd.x) < COINCIDENT_EPS;
4222
+ const isHorizontal5 = Math.abs(pathStart.y - pathEnd.y) < COINCIDENT_EPS;
4223
+ if (!isVertical6 && !isHorizontal5) continue;
4224
+ const pathBounds = getStrokeBounds(pathStart, pathEnd, isVertical6);
4225
4225
  for (const trace of traces) {
4226
4226
  for (let traceIndex = 0; traceIndex < trace.tracePath.length - 1; traceIndex++) {
4227
4227
  const traceStart = trace.tracePath[traceIndex];
4228
4228
  const traceEnd = trace.tracePath[traceIndex + 1];
4229
- const isParallel = isVertical5 ? Math.abs(traceStart.x - traceEnd.x) < COINCIDENT_EPS : Math.abs(traceStart.y - traceEnd.y) < COINCIDENT_EPS;
4229
+ const isParallel = isVertical6 ? Math.abs(traceStart.x - traceEnd.x) < COINCIDENT_EPS : Math.abs(traceStart.y - traceEnd.y) < COINCIDENT_EPS;
4230
4230
  if (!isParallel) continue;
4231
4231
  const overlap = boundsIntersection(
4232
4232
  pathBounds,
4233
- getStrokeBounds(traceStart, traceEnd, isVertical5)
4233
+ getStrokeBounds(traceStart, traceEnd, isVertical6)
4234
4234
  );
4235
4235
  if (!overlap) continue;
4236
- const overlapLength = isVertical5 ? overlap.maxY - overlap.minY : overlap.maxX - overlap.minX;
4236
+ const overlapLength = isVertical6 ? overlap.maxY - overlap.minY : overlap.maxX - overlap.minX;
4237
4237
  if (overlapLength > COINCIDENT_EPS) return true;
4238
4238
  }
4239
4239
  }
@@ -6015,12 +6015,12 @@ var EPS8 = 1e-9;
6015
6015
 
6016
6016
  // lib/solvers/Example28Solver/segmentRunsAlongRectBoundary.ts
6017
6017
  var segmentRunsAlongRectBoundary = (start, end, rect) => {
6018
- const isVertical5 = Math.abs(start.x - end.x) < EPS8;
6019
- const isHorizontal4 = Math.abs(start.y - end.y) < EPS8;
6020
- if (isVertical5) {
6018
+ const isVertical6 = Math.abs(start.x - end.x) < EPS8;
6019
+ const isHorizontal5 = Math.abs(start.y - end.y) < EPS8;
6020
+ if (isVertical6) {
6021
6021
  return Math.abs(start.x - rect.minX) < EPS8 || Math.abs(start.x - rect.maxX) < EPS8;
6022
6022
  }
6023
- if (isHorizontal4) {
6023
+ if (isHorizontal5) {
6024
6024
  return Math.abs(start.y - rect.minY) < EPS8 || Math.abs(start.y - rect.maxY) < EPS8;
6025
6025
  }
6026
6026
  return false;
@@ -6614,12 +6614,12 @@ var findPerpendicularPathCrossings = (path, otherPath) => {
6614
6614
  for (let pathSegmentIndex = 1; pathSegmentIndex < path.length - 2; pathSegmentIndex++) {
6615
6615
  const start = path[pathSegmentIndex];
6616
6616
  const end = path[pathSegmentIndex + 1];
6617
- const isVertical5 = Math.abs(start.x - end.x) < EPS9;
6617
+ const isVertical6 = Math.abs(start.x - end.x) < EPS9;
6618
6618
  for (let otherPathSegmentIndex = 1; otherPathSegmentIndex < otherPath.length - 2; otherPathSegmentIndex++) {
6619
6619
  const otherStart = otherPath[otherPathSegmentIndex];
6620
6620
  const otherEnd = otherPath[otherPathSegmentIndex + 1];
6621
6621
  const otherIsVertical = Math.abs(otherStart.x - otherEnd.x) < EPS9;
6622
- if (isVertical5 === otherIsVertical) continue;
6622
+ if (isVertical6 === otherIsVertical) continue;
6623
6623
  const intersection = getSegmentIntersection(
6624
6624
  start,
6625
6625
  end,
@@ -7727,8 +7727,8 @@ var getChipBoundaryOverlap = (path, chipObstacles) => {
7727
7727
  return total;
7728
7728
  };
7729
7729
  var getSegmentOverlapWithRectSpan = (start, end, rect) => {
7730
- const isVertical5 = Math.abs(start.x - end.x) < EPS8;
7731
- if (isVertical5) {
7730
+ const isVertical6 = Math.abs(start.x - end.x) < EPS8;
7731
+ if (isVertical6) {
7732
7732
  return Math.min(Math.max(start.y, end.y), rect.maxY) - Math.max(Math.min(start.y, end.y), rect.minY);
7733
7733
  }
7734
7734
  return Math.min(Math.max(start.x, end.x), rect.maxX) - Math.max(Math.min(start.x, end.x), rect.minX);
@@ -11978,11 +11978,11 @@ var NetLabelNetLabelCollisionSolver = class extends BaseSolver {
11978
11978
  for (let si = 0; si < pts.length - 1; si++) {
11979
11979
  const segStart = pts[si];
11980
11980
  const segEnd = pts[si + 1];
11981
- const isHorizontal4 = Math.abs(segStart.y - segEnd.y) < SEGMENT_PARALLEL_EPS;
11982
- const isVertical5 = Math.abs(segStart.x - segEnd.x) < SEGMENT_PARALLEL_EPS;
11983
- if (!isHorizontal4 && !isVertical5) continue;
11981
+ const isHorizontal5 = Math.abs(segStart.y - segEnd.y) < SEGMENT_PARALLEL_EPS;
11982
+ const isVertical6 = Math.abs(segStart.x - segEnd.x) < SEGMENT_PARALLEL_EPS;
11983
+ if (!isHorizontal5 && !isVertical6) continue;
11984
11984
  let perpendicularOrientations;
11985
- if (isHorizontal4) {
11985
+ if (isHorizontal5) {
11986
11986
  perpendicularOrientations = ["y+", "y-"];
11987
11987
  } else {
11988
11988
  perpendicularOrientations = ["x+", "x-"];
@@ -13660,9 +13660,9 @@ var getStubLength = (path) => {
13660
13660
  return Math.abs(end.x - start.x) + Math.abs(end.y - start.y);
13661
13661
  };
13662
13662
  var getLabelBounds2 = (placement) => {
13663
- const isVertical5 = placement.axis === "y";
13664
- const width = isVertical5 ? placement.height : placement.width;
13665
- const height = isVertical5 ? placement.width : placement.height;
13663
+ const isVertical6 = placement.axis === "y";
13664
+ const width = isVertical6 ? placement.height : placement.width;
13665
+ const height = isVertical6 ? placement.width : placement.height;
13666
13666
  return {
13667
13667
  minX: placement.center.x - width / 2,
13668
13668
  maxX: placement.center.x + width / 2,
@@ -13890,9 +13890,9 @@ var isPointOnPath2 = (point, path) => {
13890
13890
  const maxX = Math.max(start.x, end.x) + POINT_EPSILON;
13891
13891
  const minY = Math.min(start.y, end.y) - POINT_EPSILON;
13892
13892
  const maxY = Math.max(start.y, end.y) + POINT_EPSILON;
13893
- const isHorizontal4 = Math.abs(start.y - end.y) <= POINT_EPSILON;
13894
- const isVertical5 = Math.abs(start.x - end.x) <= POINT_EPSILON;
13895
- if ((isHorizontal4 && Math.abs(point.y - start.y) <= POINT_EPSILON || isVertical5 && Math.abs(point.x - start.x) <= POINT_EPSILON) && point.x >= minX && point.x <= maxX && point.y >= minY && point.y <= maxY) {
13893
+ const isHorizontal5 = Math.abs(start.y - end.y) <= POINT_EPSILON;
13894
+ const isVertical6 = Math.abs(start.x - end.x) <= POINT_EPSILON;
13895
+ if ((isHorizontal5 && Math.abs(point.y - start.y) <= POINT_EPSILON || isVertical6 && Math.abs(point.x - start.x) <= POINT_EPSILON) && point.x >= minX && point.x <= maxX && point.y >= minY && point.y <= maxY) {
13896
13896
  return true;
13897
13897
  }
13898
13898
  }
@@ -15127,10 +15127,10 @@ orientation: ${label.orientation}`
15127
15127
  strokeColor: "purple"
15128
15128
  });
15129
15129
  }
15130
- const isHorizontal4 = inlineLabel.axis === "x";
15130
+ const isHorizontal5 = inlineLabel.axis === "x";
15131
15131
  let renderedWidth = inlineLabel.width;
15132
15132
  let renderedHeight = inlineLabel.height;
15133
- if (!isHorizontal4) {
15133
+ if (!isHorizontal5) {
15134
15134
  renderedWidth = inlineLabel.height;
15135
15135
  renderedHeight = inlineLabel.width;
15136
15136
  }
@@ -15230,9 +15230,9 @@ var getCollisionLimitedTerminalStubEnd = ({
15230
15230
  ownGlobalConnNetId,
15231
15231
  ignoredTraceIds
15232
15232
  }) => {
15233
- const isHorizontal4 = Math.abs(intendedEnd.x - start.x) >= Math.abs(intendedEnd.y - start.y);
15234
- const alongAxis = isHorizontal4 ? "x" : "y";
15235
- const acrossAxis = isHorizontal4 ? "y" : "x";
15233
+ const isHorizontal5 = Math.abs(intendedEnd.x - start.x) >= Math.abs(intendedEnd.y - start.y);
15234
+ const alongAxis = isHorizontal5 ? "x" : "y";
15235
+ const acrossAxis = isHorizontal5 ? "y" : "x";
15236
15236
  const direction = Math.sign(intendedEnd[alongAxis] - start[alongAxis]) || 1;
15237
15237
  const intendedLength = Math.abs(intendedEnd[alongAxis] - start[alongAxis]);
15238
15238
  let availableLength = intendedLength;
@@ -15270,7 +15270,7 @@ var getCollisionLimitedTerminalStubEnd = ({
15270
15270
  }
15271
15271
  }
15272
15272
  if (availableLength + GEOMETRY_EPSILON < minimumLength) return null;
15273
- return isHorizontal4 ? { x: start.x + direction * availableLength, y: start.y } : { x: start.x, y: start.y + direction * availableLength };
15273
+ return isHorizontal5 ? { x: start.x + direction * availableLength, y: start.y } : { x: start.x, y: start.y + direction * availableLength };
15274
15274
  };
15275
15275
 
15276
15276
  // lib/solvers/NetLabelToTraceSolver/NetLabelToTraceSolver.ts
@@ -15279,23 +15279,6 @@ import {
15279
15279
  getBoundFromCenteredRect
15280
15280
  } from "@tscircuit/math-utils";
15281
15281
 
15282
- // lib/solvers/NetLabelTraceRecovery/getTraceRecoveryConnectivityMaps.ts
15283
- var getTraceRecoveryConnectivityMaps = (inputProblem) => {
15284
- const chipMap = {};
15285
- const pinMap = /* @__PURE__ */ new Map();
15286
- for (const chip of inputProblem.chips) {
15287
- chipMap[chip.chipId] = chip;
15288
- for (const pin of chip.pins) {
15289
- pinMap.set(pin.pinId, {
15290
- ...pin,
15291
- chipId: chip.chipId,
15292
- _facingDirection: pin._facingDirection ?? getPinDirection(pin, chip)
15293
- });
15294
- }
15295
- }
15296
- return { chipMap, pinMap };
15297
- };
15298
-
15299
15282
  // lib/solvers/NetLabelTraceRecovery/doesTraceRecoveryPathConflict.ts
15300
15283
  import { doSegmentsIntersect as doSegmentsIntersect4 } from "@tscircuit/math-utils";
15301
15284
  var EPSILON = 1e-6;
@@ -15372,6 +15355,124 @@ var doesTraceRecoveryPathConflict = (tracePath, collisionTraces) => {
15372
15355
  return false;
15373
15356
  };
15374
15357
 
15358
+ // lib/solvers/NetLabelTraceRecovery/getTraceRecoveryConnectivityMaps.ts
15359
+ var getTraceRecoveryConnectivityMaps = (inputProblem) => {
15360
+ const chipMap = {};
15361
+ const pinMap = /* @__PURE__ */ new Map();
15362
+ for (const chip of inputProblem.chips) {
15363
+ chipMap[chip.chipId] = chip;
15364
+ for (const pin of chip.pins) {
15365
+ pinMap.set(pin.pinId, {
15366
+ ...pin,
15367
+ chipId: chip.chipId,
15368
+ _facingDirection: pin._facingDirection ?? getPinDirection(pin, chip)
15369
+ });
15370
+ }
15371
+ }
15372
+ return { chipMap, pinMap };
15373
+ };
15374
+
15375
+ // lib/solvers/NetLabelToTraceSolver/reduceTraceCrossings.ts
15376
+ var EPS14 = 1e-9;
15377
+ var isHorizontal4 = (start, end) => Math.abs(start.y - end.y) < EPS14;
15378
+ var isVertical5 = (start, end) => Math.abs(start.x - end.x) < EPS14;
15379
+ var compactConsecutivePoints = (path) => path.filter((point, index) => {
15380
+ const previousPoint = path[index - 1];
15381
+ return !previousPoint || Math.abs(point.x - previousPoint.x) >= EPS14 || Math.abs(point.y - previousPoint.y) >= EPS14;
15382
+ });
15383
+ var isValidOrthogonalPath = (path) => {
15384
+ if (path.length < 2 || !path.every((point, index) => {
15385
+ const nextPoint = path[index + 1];
15386
+ if (!nextPoint) return true;
15387
+ return isHorizontal4(point, nextPoint) || isVertical5(point, nextPoint);
15388
+ })) {
15389
+ return false;
15390
+ }
15391
+ for (let firstSegmentIndex = 0; firstSegmentIndex < path.length - 1; firstSegmentIndex++) {
15392
+ for (let secondSegmentIndex = firstSegmentIndex + 2; secondSegmentIndex < path.length - 1; secondSegmentIndex++) {
15393
+ if (segmentsIntersect(
15394
+ path[firstSegmentIndex],
15395
+ path[firstSegmentIndex + 1],
15396
+ path[secondSegmentIndex],
15397
+ path[secondSegmentIndex + 1]
15398
+ )) {
15399
+ return false;
15400
+ }
15401
+ }
15402
+ }
15403
+ return true;
15404
+ };
15405
+ var getEndpointAlignedSegmentCandidates = (tracePath) => {
15406
+ const candidates = [];
15407
+ for (let segmentIndex = 2; segmentIndex <= tracePath.length - 4; segmentIndex++) {
15408
+ const previousPoint = tracePath[segmentIndex - 1];
15409
+ const start = tracePath[segmentIndex];
15410
+ const end = tracePath[segmentIndex + 1];
15411
+ const nextPoint = tracePath[segmentIndex + 2];
15412
+ const segmentIsVertical = isVertical5(start, end);
15413
+ const segmentIsHorizontal = isHorizontal4(start, end);
15414
+ if (!segmentIsVertical && !segmentIsHorizontal || segmentIsVertical && (!isHorizontal4(previousPoint, start) || !isHorizontal4(end, nextPoint)) || segmentIsHorizontal && (!isVertical5(previousPoint, start) || !isVertical5(end, nextPoint))) {
15415
+ continue;
15416
+ }
15417
+ const alignedCoordinates = segmentIsVertical ? [previousPoint.x, nextPoint.x] : [previousPoint.y, nextPoint.y];
15418
+ for (const alignedCoordinate of alignedCoordinates) {
15419
+ if (Math.abs(alignedCoordinate - (segmentIsVertical ? start.x : start.y)) < EPS14) {
15420
+ continue;
15421
+ }
15422
+ const candidate = tracePath.map((point) => ({ ...point }));
15423
+ if (segmentIsVertical) {
15424
+ candidate[segmentIndex].x = alignedCoordinate;
15425
+ candidate[segmentIndex + 1].x = alignedCoordinate;
15426
+ } else {
15427
+ candidate[segmentIndex].y = alignedCoordinate;
15428
+ candidate[segmentIndex + 1].y = alignedCoordinate;
15429
+ }
15430
+ const compactedCandidate = compactConsecutivePoints(candidate);
15431
+ if (isValidOrthogonalPath(compactedCandidate)) {
15432
+ candidates.push(compactedCandidate);
15433
+ }
15434
+ }
15435
+ }
15436
+ return candidates;
15437
+ };
15438
+ var countOtherNetCrossings2 = ({
15439
+ tracePath,
15440
+ globalConnNetId,
15441
+ otherTraces
15442
+ }) => otherTraces.reduce(
15443
+ (crossingCount, otherTrace) => crossingCount + (otherTrace.globalConnNetId === globalConnNetId ? 0 : countPathIntersections(tracePath, otherTrace.tracePath)),
15444
+ 0
15445
+ );
15446
+ var reduceTraceCrossings = ({
15447
+ tracePath,
15448
+ globalConnNetId,
15449
+ otherTraces,
15450
+ isCandidateValid
15451
+ }) => {
15452
+ let bestPath = tracePath;
15453
+ let bestCrossingCount = countOtherNetCrossings2({
15454
+ tracePath,
15455
+ globalConnNetId,
15456
+ otherTraces
15457
+ });
15458
+ let bestPathLength = getPathLength2(tracePath);
15459
+ for (const candidate of getEndpointAlignedSegmentCandidates(tracePath)) {
15460
+ if (!isCandidateValid(candidate)) continue;
15461
+ const crossingCount = countOtherNetCrossings2({
15462
+ tracePath: candidate,
15463
+ globalConnNetId,
15464
+ otherTraces
15465
+ });
15466
+ const pathLength = getPathLength2(candidate);
15467
+ if (crossingCount < bestCrossingCount || crossingCount === bestCrossingCount && pathLength < bestPathLength) {
15468
+ bestPath = candidate;
15469
+ bestCrossingCount = crossingCount;
15470
+ bestPathLength = pathLength;
15471
+ }
15472
+ }
15473
+ return bestPath;
15474
+ };
15475
+
15375
15476
  // lib/solvers/NetLabelToTraceSolver/NetLabelToTraceSolver.ts
15376
15477
  var AVAILABLE_NET_ORIENTATION_PREFIX = "available-net-orientation-";
15377
15478
  var RECOVERED_TRACE_PREFIX = "net-label-to-trace-";
@@ -15631,7 +15732,7 @@ var NetLabelToTraceSolver = class extends BaseSolver {
15631
15732
  }
15632
15733
  tryAcceptCurrentRoute() {
15633
15734
  const candidate = this.currentCandidate;
15634
- const tracePath = this.activeSubSolver?.solvedTracePath;
15735
+ let tracePath = this.activeSubSolver?.solvedTracePath;
15635
15736
  if (!candidate || !tracePath) return;
15636
15737
  const retainedTraces = this.outputTraces.filter(
15637
15738
  (trace) => !this.isSupersededConnectorTrace(trace, candidate)
@@ -15645,6 +15746,12 @@ var NetLabelToTraceSolver = class extends BaseSolver {
15645
15746
  if (doesTraceRecoveryPathConflict(tracePath, collisionTraces) || this.routeIntersectsRemainingLabels(tracePath, candidate)) {
15646
15747
  return;
15647
15748
  }
15749
+ tracePath = reduceTraceCrossings({
15750
+ tracePath,
15751
+ globalConnNetId: candidate.firstLabel.globalConnNetId,
15752
+ otherTraces: collisionTraces,
15753
+ isCandidateValid: (candidatePath) => findFirstCollision(candidatePath, this.activeSubSolver.obstacles) === null && !doesTraceRecoveryPathConflict(candidatePath, collisionTraces) && !this.routeIntersectsRemainingLabels(candidatePath, candidate)
15754
+ });
15648
15755
  const [firstPin, secondPin] = candidate.pins;
15649
15756
  const mspPairId = `${RECOVERED_TRACE_PREFIX}${candidate.key}`;
15650
15757
  const recoveredTrace = {
@@ -5,16 +5,17 @@ import {
5
5
  } from "@tscircuit/math-utils"
6
6
  import type { GraphicsObject } from "graphics-debug"
7
7
  import { BaseSolver } from "lib/solvers/BaseSolver/BaseSolver"
8
- import { getConnectivityMapsFromInputProblem } from "lib/solvers/MspConnectionPairSolver/getConnectivityMapFromInputProblem"
9
8
  import { doesPairCrossRestrictedCenterLines } from "lib/solvers/MspConnectionPairSolver/doesPairCrossRestrictedCenterLines"
9
+ import { getConnectivityMapsFromInputProblem } from "lib/solvers/MspConnectionPairSolver/getConnectivityMapFromInputProblem"
10
10
  import type { NetLabelPlacement } from "lib/solvers/NetLabelPlacementSolver/NetLabelPlacementSolver"
11
+ import { doesTraceRecoveryPathConflict } from "lib/solvers/NetLabelTraceRecovery/doesTraceRecoveryPathConflict"
11
12
  import {
12
13
  getTraceRecoveryConnectivityMaps,
13
14
  type TraceRecoveryPin,
14
15
  } from "lib/solvers/NetLabelTraceRecovery/getTraceRecoveryConnectivityMaps"
15
- import { doesTraceRecoveryPathConflict } from "lib/solvers/NetLabelTraceRecovery/doesTraceRecoveryPathConflict"
16
16
  import { getTraceConnectedPinComponents } from "lib/solvers/SchematicTraceLinesSolver/getTraceConnectedPinComponents"
17
17
  import type { SolvedTracePath } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceLinesSolver"
18
+ import { findFirstCollision } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/collisions"
18
19
  import { SchematicTraceSingleLineSolver2 } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/SchematicTraceSingleLineSolver2"
19
20
  import type {
20
21
  ChipId,
@@ -24,10 +25,11 @@ import type {
24
25
  } from "lib/types/InputProblem"
25
26
  import { arePinsInDifferentSchematicSections } from "lib/utils/arePinsInDifferentSchematicSections"
26
27
  import {
27
- type InlineNetLabelPlacement,
28
28
  type InlineNetLabelOutput,
29
+ type InlineNetLabelPlacement,
29
30
  visualizeInlineNetLabelOutput,
30
31
  } from "../InlineNetLabelSolver/InlineNetLabelSolver"
32
+ import { reduceTraceCrossings } from "./reduceTraceCrossings"
31
33
 
32
34
  type GlobalConnNetId = NetLabelPlacement["globalConnNetId"]
33
35
 
@@ -420,7 +422,7 @@ export class NetLabelToTraceSolver extends BaseSolver {
420
422
 
421
423
  private tryAcceptCurrentRoute() {
422
424
  const candidate = this.currentCandidate
423
- const tracePath = this.activeSubSolver?.solvedTracePath
425
+ let tracePath = this.activeSubSolver?.solvedTracePath
424
426
  if (!candidate || !tracePath) return
425
427
 
426
428
  const retainedTraces = this.outputTraces.filter(
@@ -440,6 +442,17 @@ export class NetLabelToTraceSolver extends BaseSolver {
440
442
  return
441
443
  }
442
444
 
445
+ tracePath = reduceTraceCrossings({
446
+ tracePath,
447
+ globalConnNetId: candidate.firstLabel.globalConnNetId,
448
+ otherTraces: collisionTraces,
449
+ isCandidateValid: (candidatePath) =>
450
+ findFirstCollision(candidatePath, this.activeSubSolver!.obstacles) ===
451
+ null &&
452
+ !doesTraceRecoveryPathConflict(candidatePath, collisionTraces) &&
453
+ !this.routeIntersectsRemainingLabels(candidatePath, candidate),
454
+ })
455
+
443
456
  const [firstPin, secondPin] = candidate.pins
444
457
  const mspPairId = `${RECOVERED_TRACE_PREFIX}${candidate.key}`
445
458
  const recoveredTrace: SolvedTracePath = {
@@ -0,0 +1,180 @@
1
+ import type { Point } from "@tscircuit/math-utils"
2
+ import {
3
+ countPathIntersections,
4
+ getPathLength,
5
+ segmentsIntersect,
6
+ } from "lib/solvers/Example28Solver/geometry"
7
+ import type { SolvedTracePath } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceLinesSolver"
8
+
9
+ const EPS = 1e-9
10
+
11
+ const isHorizontal = (start: Point, end: Point) =>
12
+ Math.abs(start.y - end.y) < EPS
13
+
14
+ const isVertical = (start: Point, end: Point) => Math.abs(start.x - end.x) < EPS
15
+
16
+ const compactConsecutivePoints = (path: Point[]) =>
17
+ path.filter((point, index) => {
18
+ const previousPoint = path[index - 1]
19
+ return (
20
+ !previousPoint ||
21
+ Math.abs(point.x - previousPoint.x) >= EPS ||
22
+ Math.abs(point.y - previousPoint.y) >= EPS
23
+ )
24
+ })
25
+
26
+ const isValidOrthogonalPath = (path: Point[]) => {
27
+ if (
28
+ path.length < 2 ||
29
+ !path.every((point, index) => {
30
+ const nextPoint = path[index + 1]
31
+ if (!nextPoint) return true
32
+ return isHorizontal(point, nextPoint) || isVertical(point, nextPoint)
33
+ })
34
+ ) {
35
+ return false
36
+ }
37
+
38
+ for (
39
+ let firstSegmentIndex = 0;
40
+ firstSegmentIndex < path.length - 1;
41
+ firstSegmentIndex++
42
+ ) {
43
+ for (
44
+ let secondSegmentIndex = firstSegmentIndex + 2;
45
+ secondSegmentIndex < path.length - 1;
46
+ secondSegmentIndex++
47
+ ) {
48
+ if (
49
+ segmentsIntersect(
50
+ path[firstSegmentIndex]!,
51
+ path[firstSegmentIndex + 1]!,
52
+ path[secondSegmentIndex]!,
53
+ path[secondSegmentIndex + 1]!,
54
+ )
55
+ ) {
56
+ return false
57
+ }
58
+ }
59
+ }
60
+
61
+ return true
62
+ }
63
+
64
+ const getEndpointAlignedSegmentCandidates = (tracePath: Point[]) => {
65
+ const candidates: Point[][] = []
66
+
67
+ // Preserve the terminal segment at each pin. For an interior segment whose
68
+ // neighboring segments are perpendicular, align it with either neighboring
69
+ // endpoint corridor. This keeps the same orthogonal topology while allowing
70
+ // a midpoint elbow to move away from avoidable trace crossings.
71
+ for (
72
+ let segmentIndex = 2;
73
+ segmentIndex <= tracePath.length - 4;
74
+ segmentIndex++
75
+ ) {
76
+ const previousPoint = tracePath[segmentIndex - 1]!
77
+ const start = tracePath[segmentIndex]!
78
+ const end = tracePath[segmentIndex + 1]!
79
+ const nextPoint = tracePath[segmentIndex + 2]!
80
+ const segmentIsVertical = isVertical(start, end)
81
+ const segmentIsHorizontal = isHorizontal(start, end)
82
+
83
+ if (
84
+ (!segmentIsVertical && !segmentIsHorizontal) ||
85
+ (segmentIsVertical &&
86
+ (!isHorizontal(previousPoint, start) ||
87
+ !isHorizontal(end, nextPoint))) ||
88
+ (segmentIsHorizontal &&
89
+ (!isVertical(previousPoint, start) || !isVertical(end, nextPoint)))
90
+ ) {
91
+ continue
92
+ }
93
+
94
+ const alignedCoordinates = segmentIsVertical
95
+ ? [previousPoint.x, nextPoint.x]
96
+ : [previousPoint.y, nextPoint.y]
97
+ for (const alignedCoordinate of alignedCoordinates) {
98
+ if (
99
+ Math.abs(alignedCoordinate - (segmentIsVertical ? start.x : start.y)) <
100
+ EPS
101
+ ) {
102
+ continue
103
+ }
104
+
105
+ const candidate = tracePath.map((point) => ({ ...point }))
106
+ if (segmentIsVertical) {
107
+ candidate[segmentIndex]!.x = alignedCoordinate
108
+ candidate[segmentIndex + 1]!.x = alignedCoordinate
109
+ } else {
110
+ candidate[segmentIndex]!.y = alignedCoordinate
111
+ candidate[segmentIndex + 1]!.y = alignedCoordinate
112
+ }
113
+
114
+ const compactedCandidate = compactConsecutivePoints(candidate)
115
+ if (isValidOrthogonalPath(compactedCandidate)) {
116
+ candidates.push(compactedCandidate)
117
+ }
118
+ }
119
+ }
120
+
121
+ return candidates
122
+ }
123
+
124
+ const countOtherNetCrossings = ({
125
+ tracePath,
126
+ globalConnNetId,
127
+ otherTraces,
128
+ }: {
129
+ tracePath: Point[]
130
+ globalConnNetId: string
131
+ otherTraces: SolvedTracePath[]
132
+ }) =>
133
+ otherTraces.reduce(
134
+ (crossingCount, otherTrace) =>
135
+ crossingCount +
136
+ (otherTrace.globalConnNetId === globalConnNetId
137
+ ? 0
138
+ : countPathIntersections(tracePath, otherTrace.tracePath)),
139
+ 0,
140
+ )
141
+
142
+ export const reduceTraceCrossings = ({
143
+ tracePath,
144
+ globalConnNetId,
145
+ otherTraces,
146
+ isCandidateValid,
147
+ }: {
148
+ tracePath: Point[]
149
+ globalConnNetId: string
150
+ otherTraces: SolvedTracePath[]
151
+ isCandidateValid: (candidate: Point[]) => boolean
152
+ }) => {
153
+ let bestPath = tracePath
154
+ let bestCrossingCount = countOtherNetCrossings({
155
+ tracePath,
156
+ globalConnNetId,
157
+ otherTraces,
158
+ })
159
+ let bestPathLength = getPathLength(tracePath)
160
+
161
+ for (const candidate of getEndpointAlignedSegmentCandidates(tracePath)) {
162
+ if (!isCandidateValid(candidate)) continue
163
+ const crossingCount = countOtherNetCrossings({
164
+ tracePath: candidate,
165
+ globalConnNetId,
166
+ otherTraces,
167
+ })
168
+ const pathLength = getPathLength(candidate)
169
+ if (
170
+ crossingCount < bestCrossingCount ||
171
+ (crossingCount === bestCrossingCount && pathLength < bestPathLength)
172
+ ) {
173
+ bestPath = candidate
174
+ bestCrossingCount = crossingCount
175
+ bestPathLength = pathLength
176
+ }
177
+ }
178
+
179
+ return bestPath
180
+ }
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "url": "https://github.com/tscircuit/schematic-trace-solver.git"
6
6
  },
7
7
  "main": "dist/index.js",
8
- "version": "0.0.169",
8
+ "version": "0.0.170",
9
9
  "type": "module",
10
10
  "scripts": {
11
11
  "start": "cosmos",
@@ -1,6 +1,6 @@
1
1
  <svg width="1200" height="2016" viewBox="0 0 1200 2016" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Solver debug visualization on top and Circuit JSON schematic on the bottom">
2
2
  <g transform="translate(0, 0) scale(1.875, 1.875) translate(0, 0)">
3
- <rect width="100%" height="100%" fill="white"/><g><polyline data-points="-6.74,0.3 -4.24,1.7" data-type="line" data-label="" points="61.98952879581145,334.4564787958115 245.23560209424073,231.8386777486911" fill="none" stroke="hsl(24, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="-0.6000000000000001,0.30000000000000004 -5.640000000000001,0.3" data-type="line" data-label="" points="512.0418848167538,334.4564787958115 142.61780104712034,334.4564787958115" fill="none" stroke="hsl(8, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="-0.6000000000000001,0.10000000000000003 -3.1399999999999997,1.7" data-type="line" data-label="" points="512.0418848167538,349.11616465968586 325.8638743455497,231.8386777486911" fill="none" stroke="hsl(8, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="-3.52,-0.09999999999999998 -0.6000000000000001,-0.09999999999999998" data-type="line" data-label="" points="298.01047120418843,363.77585052356017 512.0418848167538,363.77585052356017" fill="none" stroke="hsl(152, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="-3.52,-0.3 -0.6000000000000001,-0.30000000000000004" data-type="line" data-label="" points="298.01047120418843,378.4355363874345 512.0418848167538,378.4355363874345" fill="none" stroke="hsl(152, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="-6.74,0.3 -6.94,0.3 -6.94,1.7 -4.24,1.7" data-type="line" data-label="" points="61.98952879581145,334.4564787958115 47.329842931937094,334.4564787958115 47.329842931937094,231.8386777486911 245.23560209424073,231.8386777486911" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="-0.6000000000000001,0.30000000000000004 -5.640000000000001,0.3" data-type="line" data-label="" points="512.0418848167538,334.4564787958115 142.61780104712034,334.4564787958115" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="-3.52,-0.09999999999999998 -3.72,-0.09999999999999998 -3.72,0.19999999999999998 -1.1510000000000002,0.19999999999999998 -1.1510000000000002,-0.09999999999999998 -0.6000000000000005,-0.09999999999999998" data-type="line" data-label="" points="298.01047120418843,363.77585052356017 283.3507853403141,363.77585052356017 283.3507853403141,341.78632172774866 471.65445026177997,341.78632172774866 471.65445026177997,363.77585052356017 512.0418848167538,363.77585052356017" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="-0.6000000000000001,0.10000000000000003 -0.8,0.10000000000000003 -1.8699999999999999,0.10000000000000003 -1.8699999999999999,1.7 -2.9399999999999995,1.7 -3.1399999999999997,1.7" data-type="line" data-label="" points="512.0418848167538,349.11616465968586 497.3821989528795,349.11616465968586 418.95287958115176,349.11616465968586 418.95287958115176,231.8386777486911 340.52356020942403,231.8386777486911 325.8638743455497,231.8386777486911" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="-0.6000000000000001,0.10000000000000003 -0.8,0.10000000000000003 -1.8699999999999999,0.10000000000000003 -1.8699999999999999,1.7 -2.9399999999999995,1.7 -3.1399999999999997,1.7" data-type="line" data-label="recovered from net labels: U1.2 -&gt; R1.2" points="512.0418848167538,349.11616465968586 497.3821989528795,349.11616465968586 418.95287958115176,349.11616465968586 418.95287958115176,231.8386777486911 340.52356020942403,231.8386777486911 325.8638743455497,231.8386777486911" fill="none" stroke="green" stroke-width="1px"/></g><g><rect data-type="rect" data-label="schematic_component_0" data-x="-3.69" data-y="1.7" x="245.23560209424076" y="217.58540602094246" width="80.62827225130894" height="28.506543455497336" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.013642857142857144"/></g><g><rect data-type="rect" data-label="schematic_component_1" data-x="-6.19" data-y="0.3" x="61.98952879581145" y="303.67113848167537" width="80.62827225130889" height="61.57068062827227" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.013642857142857144"/></g><g><rect data-type="rect" data-label="schematic_component_2" data-x="0" data-y="0" x="512.0418848167538" y="319.79679293193715" width="87.95811518324604" height="73.29842931937173" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.013642857142857144"/></g><g><rect data-type="rect" data-label="schematic_component_3" data-x="-2.92" data-y="-0.4" x="298.01047120418843" y="349.11616465968586" width="87.95811518324604" height="73.29842931937173" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.013642857142857144"/></g><g><rect data-type="rect" data-label="netId: .C1 &gt; .pin1 to R1.pin1
3
+ <rect width="100%" height="100%" fill="white"/><g><polyline data-points="-6.74,0.3 -4.24,1.7" data-type="line" data-label="" points="61.98952879581145,334.4564787958115 245.23560209424073,231.8386777486911" fill="none" stroke="hsl(24, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="-0.6000000000000001,0.30000000000000004 -5.640000000000001,0.3" data-type="line" data-label="" points="512.0418848167538,334.4564787958115 142.61780104712034,334.4564787958115" fill="none" stroke="hsl(8, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="-0.6000000000000001,0.10000000000000003 -3.1399999999999997,1.7" data-type="line" data-label="" points="512.0418848167538,349.11616465968586 325.8638743455497,231.8386777486911" fill="none" stroke="hsl(8, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="-3.52,-0.09999999999999998 -0.6000000000000001,-0.09999999999999998" data-type="line" data-label="" points="298.01047120418843,363.77585052356017 512.0418848167538,363.77585052356017" fill="none" stroke="hsl(152, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="-3.52,-0.3 -0.6000000000000001,-0.30000000000000004" data-type="line" data-label="" points="298.01047120418843,378.4355363874345 512.0418848167538,378.4355363874345" fill="none" stroke="hsl(152, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="-6.74,0.3 -6.94,0.3 -6.94,1.7 -4.24,1.7" data-type="line" data-label="" points="61.98952879581145,334.4564787958115 47.329842931937094,334.4564787958115 47.329842931937094,231.8386777486911 245.23560209424073,231.8386777486911" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="-0.6000000000000001,0.30000000000000004 -5.640000000000001,0.3" data-type="line" data-label="" points="512.0418848167538,334.4564787958115 142.61780104712034,334.4564787958115" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="-3.52,-0.09999999999999998 -3.72,-0.09999999999999998 -3.72,0.19999999999999998 -1.1510000000000002,0.19999999999999998 -1.1510000000000002,-0.09999999999999998 -0.6000000000000005,-0.09999999999999998" data-type="line" data-label="" points="298.01047120418843,363.77585052356017 283.3507853403141,363.77585052356017 283.3507853403141,341.78632172774866 471.65445026177997,341.78632172774866 471.65445026177997,363.77585052356017 512.0418848167538,363.77585052356017" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="-0.6000000000000001,0.10000000000000003 -0.8,0.10000000000000003 -0.8,1.7 -2.9399999999999995,1.7 -3.1399999999999997,1.7" data-type="line" data-label="" points="512.0418848167538,349.11616465968586 497.3821989528795,349.11616465968586 497.3821989528795,231.8386777486911 340.52356020942403,231.8386777486911 325.8638743455497,231.8386777486911" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="-0.6000000000000001,0.10000000000000003 -0.8,0.10000000000000003 -0.8,1.7 -2.9399999999999995,1.7 -3.1399999999999997,1.7" data-type="line" data-label="recovered from net labels: U1.2 -&gt; R1.2" points="512.0418848167538,349.11616465968586 497.3821989528795,349.11616465968586 497.3821989528795,231.8386777486911 340.52356020942403,231.8386777486911 325.8638743455497,231.8386777486911" fill="none" stroke="green" stroke-width="1px"/></g><g><rect data-type="rect" data-label="schematic_component_0" data-x="-3.69" data-y="1.7" x="245.23560209424076" y="217.58540602094246" width="80.62827225130894" height="28.506543455497336" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.013642857142857144"/></g><g><rect data-type="rect" data-label="schematic_component_1" data-x="-6.19" data-y="0.3" x="61.98952879581145" y="303.67113848167537" width="80.62827225130889" height="61.57068062827227" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.013642857142857144"/></g><g><rect data-type="rect" data-label="schematic_component_2" data-x="0" data-y="0" x="512.0418848167538" y="319.79679293193715" width="87.95811518324604" height="73.29842931937173" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.013642857142857144"/></g><g><rect data-type="rect" data-label="schematic_component_3" data-x="-2.92" data-y="-0.4" x="298.01047120418843" y="349.11616465968586" width="87.95811518324604" height="73.29842931937173" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.013642857142857144"/></g><g><rect data-type="rect" data-label="netId: .C1 &gt; .pin1 to R1.pin1
4
4
  globalConnNetId: connectivity_net0" data-x="-6.94" data-y="0.07499999999999998" x="39.99999999999997" y="334.45647879581145" width="14.659685863874245" height="32.98429319371729" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.013642857142857144"/></g><g><rect data-type="rect" data-label="netId: .U1 &gt; .pin1 to C1.pin2
5
5
  globalConnNetId: connectivity_net1" data-x="-3.12" data-y="0.525" x="319.9999999999999" y="301.4721856020942" width="14.659685863874415" height="32.98429319371729" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.013642857142857144"/></g><g><rect data-type="rect" data-label="netId: .U2 &gt; .pin1 to U1.pin3
6
6
  globalConnNetId: connectivity_net3" data-x="-3.9450000000000003" data-y="-0.09999999999999998" x="250.36649214659676" y="356.446007591623" width="32.98429319371729" height="14.659685863874358" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.013642857142857144"/></g><g><rect data-type="rect" data-label="netId: .U2 &gt; .pin2 to U1.pin4
@@ -87,7 +87,7 @@ orientation: x-" data-x="-0.6000000000000001" data-y="-0.30000000000000004" cx="
87
87
  .port-label { fill: rgb(0, 100, 100); }
88
88
  .component-name { fill: rgb(0, 100, 100); }
89
89
 
90
- </style><rect class="boundary" x="0" y="0" width="1200" height="800"/><g class="trace sch-trace" data-layer="base" data-circuit-json-type="schematic_trace" data-schematic-trace-id="schematic_trace_0__stack1"><path d="M 109.83981693392002 454.6338672769 L 82.3798627005201 454.6338672769 L 82.3798627005201 262.41418764310004 L 453.08924485142006 262.41418764310004" class="trace-invisible-hover-outline sch-trace-hitbox" stroke="rgb(0, 150, 0)" fill="none" stroke-width="21.967963386719997px" stroke-linecap="round" opacity="0" stroke-linejoin="round"/><path class="sch-trace-path" d="M 109.83981693392002 454.6338672769 L 82.3798627005201 454.6338672769 L 82.3798627005201 262.41418764310004 L 453.08924485142006 262.41418764310004" stroke="rgb(0, 150, 0)" fill="none" stroke-width="2.7459954233399997px" stroke-linecap="round" stroke-linejoin="round"/></g><g class="trace sch-trace" data-layer="base" data-circuit-json-type="schematic_trace" data-schematic-trace-id="schematic_trace_1__stack1"><path d="M 952.8604118993001 454.6338672769 L 260.86956521762 454.6338672769" class="trace-invisible-hover-outline sch-trace-hitbox" stroke="rgb(0, 150, 0)" fill="none" stroke-width="21.967963386719997px" stroke-linecap="round" opacity="0" stroke-linejoin="round"/><path class="sch-trace-path" d="M 952.8604118993001 454.6338672769 L 260.86956521762 454.6338672769" stroke="rgb(0, 150, 0)" fill="none" stroke-width="2.7459954233399997px" stroke-linecap="round" stroke-linejoin="round"/></g><g class="trace sch-trace" data-layer="base" data-circuit-json-type="schematic_trace" data-schematic-trace-id="schematic_trace_2__stack1"><path d="M 551.9450800916601 509.5537757437 L 524.4851258582601 509.5537757437 L 524.4851258582601 468.3638443936 L 877.2082379862829 468.3638443936 L 877.2082379862829 509.5537757437 L 952.8604118993 509.5537757437" class="trace-invisible-hover-outline sch-trace-hitbox" stroke="rgb(0, 150, 0)" fill="none" stroke-width="21.967963386719997px" stroke-linecap="round" opacity="0" stroke-linejoin="round"/><path class="sch-trace-path" d="M 551.9450800916601 509.5537757437 L 524.4851258582601 509.5537757437 L 524.4851258582601 468.3638443936 L 877.2082379862829 468.3638443936 L 877.2082379862829 509.5537757437 L 952.8604118993 509.5537757437" stroke="rgb(0, 150, 0)" fill="none" stroke-width="2.7459954233399997px" stroke-linecap="round" stroke-linejoin="round"/></g><g class="trace sch-trace" data-layer="base" data-circuit-json-type="schematic_trace" data-schematic-trace-id="schematic_trace_3__stack1"><path d="M 952.8604118993001 482.09382151029996 L 925.4004576659 482.09382151029996 L 778.48970251721 482.09382151029996 L 778.48970251721 262.41418764310004 L 631.5789473685202 262.41418764310004 L 604.11899313512 262.41418764310004" class="trace-invisible-hover-outline sch-trace-hitbox" stroke="rgb(0, 150, 0)" fill="none" stroke-width="21.967963386719997px" stroke-linecap="round" opacity="0" stroke-linejoin="round"/><path class="sch-trace-path" d="M 952.8604118993001 482.09382151029996 L 925.4004576659 482.09382151029996 L 778.48970251721 482.09382151029996 L 778.48970251721 262.41418764310004 L 631.5789473685202 262.41418764310004 L 604.11899313512 262.41418764310004" stroke="rgb(0, 150, 0)" fill="none" stroke-width="2.7459954233399997px" stroke-linecap="round" stroke-linejoin="round"/></g><g class="trace-overlays sch-trace-overlays" data-layer="overlay" data-circuit-json-type="schematic_trace" data-schematic-trace-id="schematic_trace_0__stack1"/><g class="trace-overlays sch-trace-overlays" data-layer="overlay" data-circuit-json-type="schematic_trace" data-schematic-trace-id="schematic_trace_1__stack1"/><g class="trace-overlays sch-trace-overlays" data-layer="overlay" data-circuit-json-type="schematic_trace" data-schematic-trace-id="schematic_trace_2__stack1"/><g class="trace-overlays sch-trace-overlays" data-layer="overlay" data-circuit-json-type="schematic_trace" data-schematic-trace-id="schematic_trace_3__stack1"/><g class="sch-component" data-circuit-json-type="schematic_component" data-schematic-component-id="schematic_component_0__stack1"><rect class="component-overlay sch-component-overlay" x="453.08924485142" y="242.28192219688282" width="151.02974828370003" height="40.264530892434436" fill="transparent"/><path class="sch-component-symbol-path" d="M 453.08924485142 262.41418764310004 L 478.2659038903128 262.41418764310004" stroke="rgb(132, 0, 0)" fill="none" stroke-width="2.7459954233399997px" stroke-linecap="round"/><path class="sch-component-symbol-path" d="M 578.9423340962273 262.41418764310004 L 604.11899313512 262.41418764310004" stroke="rgb(132, 0, 0)" fill="none" stroke-width="2.7459954233399997px" stroke-linecap="round"/><path class="sch-component-symbol-path" d="M 478.2659038903128 242.28192219688282 L 578.9423340962273 242.28192219688282 L 578.9423340962273 282.54645308931725 L 478.2659038903128 282.54645308931725 L 478.2659038903128 242.28192219688282" stroke="rgb(132, 0, 0)" fill="none" stroke-width="2.7459954233399997px" stroke-linecap="round"/><text class="sch-component-name sch-component-text" x="528.60411899327" y="222.13958810078003" stroke="rgb(245, 241, 237)" stroke-width="2.7459954233399997px" paint-order="stroke" fill="rgb(15, 15, 15)" font-family="sans-serif" text-anchor="middle" dominant-baseline="ideographic" font-size="24.713958810059996px">R1</text><text class="sch-component-text" x="528.60411899327" y="302.68878718542004" fill="rgb(15, 15, 15)" font-family="sans-serif" text-anchor="middle" dominant-baseline="hanging" font-size="24.713958810059996px"></text></g><g class="sch-component" data-circuit-json-type="schematic_component" data-schematic-component-id="schematic_component_1__stack1"><rect class="component-overlay sch-component-overlay" x="109.83981693392003" y="414.35423340963723" width="151.02974828369997" height="80.55926773452552" fill="transparent"/><path class="sch-component-symbol-path" d="M 260.86956521762 454.6338672769 L 200.45766590414 454.6338672769" stroke="rgb(132, 0, 0)" fill="none" stroke-width="2.7459954233399997px" stroke-linecap="round"/><path class="sch-component-symbol-path" d="M 170.25171624740003 454.6338672769 L 109.83981693392003 454.6338672769" stroke="rgb(132, 0, 0)" fill="none" stroke-width="2.7459954233399997px" stroke-linecap="round"/><path class="sch-component-symbol-path" d="M 200.45766590414 414.35423340963723 L 200.45766590414 494.91350114416275" stroke="rgb(132, 0, 0)" fill="none" stroke-width="2.7459954233399997px" stroke-linecap="round"/><path class="sch-component-symbol-path" d="M 170.25171624740003 414.35423340963723 L 170.25171624740003 494.91350114416275" stroke="rgb(132, 0, 0)" fill="none" stroke-width="2.7459954233399997px" stroke-linecap="round"/><text class="sch-component-name sch-component-text" x="185.35469107577" y="394.22196796342" stroke="rgb(245, 241, 237)" stroke-width="2.7459954233399997px" paint-order="stroke" fill="rgb(15, 15, 15)" font-family="sans-serif" text-anchor="middle" dominant-baseline="ideographic" font-size="24.713958810059996px">C1</text><text class="sch-component-text" x="185.35469107577" y="515.0457665903799" fill="rgb(15, 15, 15)" font-family="sans-serif" text-anchor="middle" dominant-baseline="hanging" font-size="24.713958810059996px"></text></g><g class="sch-component" data-circuit-json-type="schematic_component" data-schematic-component-id="schematic_component_2__stack1"><rect class="component chip sch-component-body" x="1007.7803203661" y="427.17391304349997" width="54.91990846679994" height="137.29977116700002" stroke-width="2.7459954233399997px" fill="rgb(255, 255, 194)" stroke="rgb(132, 0, 0)"/><rect class="component-overlay sch-component-overlay" x="1007.7803203661" y="427.17391304349997" width="54.91990846679994" height="137.29977116700002" fill="transparent"/><text class="sch-text" x="1035.2402745995" y="495.823798627" fill="#0f172a" text-anchor="middle" dominant-baseline="middle" font-family="sans-serif" font-size="24.713958810059996px" transform="rotate(0, 1035.2402745995, 495.823798627)">U1</text><line class="component-pin sch-component-pin sch-port-line" x1="1007.7803203661" y1="454.6338672769" x2="952.8604118993001" y2="454.6338672769" stroke-width="2.7459954233399997px"/><g class="sch-port" data-schematic-port-id="source_port_2_0__stack1"><rect x="950.1144164759601" y="451.88787185356" width="5.491990846679999" height="5.491990846679999" opacity="0"/></g><text class="pin-number sch-pin-number" x="980.3203661327" y="451.88787185356" style="font-family: sans-serif;" fill="rgb(169, 0, 0)" text-anchor="middle" dominant-baseline="auto" font-size="20.59496567505px" transform="">1</text><line class="component-pin sch-component-pin sch-port-line" x1="1007.7803203661" y1="482.09382151029996" x2="952.8604118993001" y2="482.09382151029996" stroke-width="2.7459954233399997px"/><g class="sch-port" data-schematic-port-id="source_port_2_1__stack1"><rect x="950.1144164759601" y="479.34782608695997" width="5.491990846679999" height="5.491990846679999" opacity="0"/></g><text class="pin-number sch-pin-number" x="980.3203661327" y="479.34782608695997" style="font-family: sans-serif;" fill="rgb(169, 0, 0)" text-anchor="middle" dominant-baseline="auto" font-size="20.59496567505px" transform="">2</text><line class="component-pin sch-component-pin sch-port-line" x1="1007.7803203661" y1="509.5537757437" x2="952.8604118993001" y2="509.5537757437" stroke-width="2.7459954233399997px"/><g class="sch-port" data-schematic-port-id="source_port_2_2__stack1"><rect x="950.1144164759601" y="506.80778032036" width="5.491990846679999" height="5.491990846679999" opacity="0"/></g><text class="pin-number sch-pin-number" x="980.3203661327" y="506.80778032036" style="font-family: sans-serif;" fill="rgb(169, 0, 0)" text-anchor="middle" dominant-baseline="auto" font-size="20.59496567505px" transform="">3</text><line class="component-pin sch-component-pin sch-port-line" x1="1007.7803203661" y1="537.0137299771" x2="955.60640732264" y2="537.0137299771" stroke-width="2.7459954233399997px"/><g class="sch-port" data-schematic-port-id="source_port_2_3__stack1"><circle class="component-pin sch-component-pin sch-port-terminal" cx="952.8604118993001" cy="537.0137299771" r="2.7459954233399997" stroke-width="2.7459954233399997px"/><rect x="950.1144164759601" y="534.26773455376" width="5.491990846679999" height="5.491990846679999" opacity="0"/></g><text class="pin-number sch-pin-number" x="980.3203661327" y="534.26773455376" style="font-family: sans-serif;" fill="rgb(169, 0, 0)" text-anchor="middle" dominant-baseline="auto" font-size="20.59496567505px" transform="">4</text><line class="component-pin sch-component-pin sch-port-line" x1="1062.7002288329" y1="537.0137299771" x2="1114.87414187636" y2="537.0137299771" stroke-width="2.7459954233399997px"/><g class="sch-port" data-schematic-port-id="source_port_2_4__stack1"><circle class="component-pin sch-component-pin sch-port-terminal" cx="1117.6201372997" cy="537.0137299771" r="2.7459954233399997" stroke-width="2.7459954233399997px"/><rect x="1114.87414187636" y="534.26773455376" width="5.491990846679999" height="5.491990846679999" opacity="0"/></g><text class="pin-number sch-pin-number" x="1090.1601830663" y="534.26773455376" style="font-family: sans-serif;" fill="rgb(169, 0, 0)" text-anchor="middle" dominant-baseline="auto" font-size="20.59496567505px" transform="">5</text><line class="component-pin sch-component-pin sch-port-line" x1="1062.7002288329" y1="509.5537757437" x2="1114.87414187636" y2="509.5537757437" stroke-width="2.7459954233399997px"/><g class="sch-port" data-schematic-port-id="source_port_2_5__stack1"><circle class="component-pin sch-component-pin sch-port-terminal" cx="1117.6201372997" cy="509.5537757437" r="2.7459954233399997" stroke-width="2.7459954233399997px"/><rect x="1114.87414187636" y="506.80778032036" width="5.491990846679999" height="5.491990846679999" opacity="0"/></g><text class="pin-number sch-pin-number" x="1090.1601830663" y="506.80778032036" style="font-family: sans-serif;" fill="rgb(169, 0, 0)" text-anchor="middle" dominant-baseline="auto" font-size="20.59496567505px" transform="">6</text><line class="component-pin sch-component-pin sch-port-line" x1="1062.7002288329" y1="482.09382151029996" x2="1114.87414187636" y2="482.09382151029996" stroke-width="2.7459954233399997px"/><g class="sch-port" data-schematic-port-id="source_port_2_6__stack1"><circle class="component-pin sch-component-pin sch-port-terminal" cx="1117.6201372997" cy="482.09382151029996" r="2.7459954233399997" stroke-width="2.7459954233399997px"/><rect x="1114.87414187636" y="479.34782608695997" width="5.491990846679999" height="5.491990846679999" opacity="0"/></g><text class="pin-number sch-pin-number" x="1090.1601830663" y="479.34782608695997" style="font-family: sans-serif;" fill="rgb(169, 0, 0)" text-anchor="middle" dominant-baseline="auto" font-size="20.59496567505px" transform="">7</text><line class="component-pin sch-component-pin sch-port-line" x1="1062.7002288329" y1="454.6338672769" x2="1114.87414187636" y2="454.6338672769" stroke-width="2.7459954233399997px"/><g class="sch-port" data-schematic-port-id="source_port_2_7__stack1"><circle class="component-pin sch-component-pin sch-port-terminal" cx="1117.6201372997" cy="454.6338672769" r="2.7459954233399997" stroke-width="2.7459954233399997px"/><rect x="1114.87414187636" y="451.88787185356" width="5.491990846679999" height="5.491990846679999" opacity="0"/></g><text class="pin-number sch-pin-number" x="1090.1601830663" y="451.88787185356" style="font-family: sans-serif;" fill="rgb(169, 0, 0)" text-anchor="middle" dominant-baseline="auto" font-size="20.59496567505px" transform="">8</text></g><g class="sch-component" data-circuit-json-type="schematic_component" data-schematic-component-id="schematic_component_3__stack1"><rect class="component chip sch-component-body" x="606.86498855846" y="482.09382151029996" width="54.91990846680005" height="137.29977116699996" stroke-width="2.7459954233399997px" fill="rgb(255, 255, 194)" stroke="rgb(132, 0, 0)"/><rect class="component-overlay sch-component-overlay" x="606.86498855846" y="482.09382151029996" width="54.91990846680005" height="137.29977116699996" fill="transparent"/><text class="sch-text" x="634.32494279186" y="550.7437070937999" fill="#0f172a" text-anchor="middle" dominant-baseline="middle" font-family="sans-serif" font-size="24.713958810059996px" transform="rotate(0, 634.32494279186, 550.7437070937999)">U2</text><line class="component-pin sch-component-pin sch-port-line" x1="606.86498855846" y1="509.5537757437" x2="551.9450800916601" y2="509.5537757437" stroke-width="2.7459954233399997px"/><g class="sch-port" data-schematic-port-id="source_port_3_0__stack1"><rect x="549.1990846683201" y="506.80778032036" width="5.491990846679999" height="5.491990846679999" opacity="0"/></g><text class="pin-number sch-pin-number" x="579.4050343250601" y="506.80778032036" style="font-family: sans-serif;" fill="rgb(169, 0, 0)" text-anchor="middle" dominant-baseline="auto" font-size="20.59496567505px" transform="">1</text><line class="component-pin sch-component-pin sch-port-line" x1="606.86498855846" y1="537.0137299771" x2="554.6910755150001" y2="537.0137299771" stroke-width="2.7459954233399997px"/><g class="sch-port" data-schematic-port-id="source_port_3_1__stack1"><circle class="component-pin sch-component-pin sch-port-terminal" cx="551.9450800916601" cy="537.0137299771" r="2.7459954233399997" stroke-width="2.7459954233399997px"/><rect x="549.1990846683201" y="534.26773455376" width="5.491990846679999" height="5.491990846679999" opacity="0"/></g><text class="pin-number sch-pin-number" x="579.4050343250601" y="534.26773455376" style="font-family: sans-serif;" fill="rgb(169, 0, 0)" text-anchor="middle" dominant-baseline="auto" font-size="20.59496567505px" transform="">2</text><line class="component-pin sch-component-pin sch-port-line" x1="606.86498855846" y1="564.4736842105" x2="554.6910755150001" y2="564.4736842105" stroke-width="2.7459954233399997px"/><g class="sch-port" data-schematic-port-id="source_port_3_2__stack1"><circle class="component-pin sch-component-pin sch-port-terminal" cx="551.9450800916601" cy="564.4736842105" r="2.7459954233399997" stroke-width="2.7459954233399997px"/><rect x="549.1990846683201" y="561.72768878716" width="5.491990846679999" height="5.491990846679999" opacity="0"/></g><text class="pin-number sch-pin-number" x="579.4050343250601" y="561.72768878716" style="font-family: sans-serif;" fill="rgb(169, 0, 0)" text-anchor="middle" dominant-baseline="auto" font-size="20.59496567505px" transform="">3</text><line class="component-pin sch-component-pin sch-port-line" x1="606.86498855846" y1="591.9336384439" x2="554.6910755150001" y2="591.9336384439" stroke-width="2.7459954233399997px"/><g class="sch-port" data-schematic-port-id="source_port_3_3__stack1"><circle class="component-pin sch-component-pin sch-port-terminal" cx="551.9450800916601" cy="591.9336384439" r="2.7459954233399997" stroke-width="2.7459954233399997px"/><rect x="549.1990846683201" y="589.18764302056" width="5.491990846679999" height="5.491990846679999" opacity="0"/></g><text class="pin-number sch-pin-number" x="579.4050343250601" y="589.18764302056" style="font-family: sans-serif;" fill="rgb(169, 0, 0)" text-anchor="middle" dominant-baseline="auto" font-size="20.59496567505px" transform="">4</text><line class="component-pin sch-component-pin sch-port-line" x1="661.7848970252601" y1="591.9336384439" x2="713.9588100687201" y2="591.9336384439" stroke-width="2.7459954233399997px"/><g class="sch-port" data-schematic-port-id="source_port_3_4__stack1"><circle class="component-pin sch-component-pin sch-port-terminal" cx="716.7048054920601" cy="591.9336384439" r="2.7459954233399997" stroke-width="2.7459954233399997px"/><rect x="713.9588100687201" y="589.18764302056" width="5.491990846679999" height="5.491990846679999" opacity="0"/></g><text class="pin-number sch-pin-number" x="689.24485125866" y="589.18764302056" style="font-family: sans-serif;" fill="rgb(169, 0, 0)" text-anchor="middle" dominant-baseline="auto" font-size="20.59496567505px" transform="">5</text><line class="component-pin sch-component-pin sch-port-line" x1="661.7848970252601" y1="564.4736842105" x2="713.9588100687201" y2="564.4736842105" stroke-width="2.7459954233399997px"/><g class="sch-port" data-schematic-port-id="source_port_3_5__stack1"><circle class="component-pin sch-component-pin sch-port-terminal" cx="716.7048054920601" cy="564.4736842105" r="2.7459954233399997" stroke-width="2.7459954233399997px"/><rect x="713.9588100687201" y="561.72768878716" width="5.491990846679999" height="5.491990846679999" opacity="0"/></g><text class="pin-number sch-pin-number" x="689.24485125866" y="561.72768878716" style="font-family: sans-serif;" fill="rgb(169, 0, 0)" text-anchor="middle" dominant-baseline="auto" font-size="20.59496567505px" transform="">6</text><line class="component-pin sch-component-pin sch-port-line" x1="661.7848970252601" y1="537.0137299771" x2="713.9588100687201" y2="537.0137299771" stroke-width="2.7459954233399997px"/><g class="sch-port" data-schematic-port-id="source_port_3_6__stack1"><circle class="component-pin sch-component-pin sch-port-terminal" cx="716.7048054920601" cy="537.0137299771" r="2.7459954233399997" stroke-width="2.7459954233399997px"/><rect x="713.9588100687201" y="534.26773455376" width="5.491990846679999" height="5.491990846679999" opacity="0"/></g><text class="pin-number sch-pin-number" x="689.24485125866" y="534.26773455376" style="font-family: sans-serif;" fill="rgb(169, 0, 0)" text-anchor="middle" dominant-baseline="auto" font-size="20.59496567505px" transform="">7</text><line class="component-pin sch-component-pin sch-port-line" x1="661.7848970252601" y1="509.5537757437" x2="713.9588100687201" y2="509.5537757437" stroke-width="2.7459954233399997px"/><g class="sch-port" data-schematic-port-id="source_port_3_7__stack1"><circle class="component-pin sch-component-pin sch-port-terminal" cx="716.7048054920601" cy="509.5537757437" r="2.7459954233399997" stroke-width="2.7459954233399997px"/><rect x="713.9588100687201" y="506.80778032036" width="5.491990846679999" height="5.491990846679999" opacity="0"/></g><text class="pin-number sch-pin-number" x="689.24485125866" y="506.80778032036" style="font-family: sans-serif;" fill="rgb(169, 0, 0)" text-anchor="middle" dominant-baseline="auto" font-size="20.59496567505px" transform="">8</text></g><g class="schematic-port-hover sch-port-hover" data-schematic-port-id="source_port_0_0__stack1"><circle cx="487.41418764317007" cy="262.41418764310004" r="5.491990846679999" fill="red" opacity="0"/></g><g class="schematic-port-hover sch-port-hover" data-schematic-port-id="source_port_0_1__stack1"><circle cx="638.4439359268702" cy="262.41418764310004" r="5.491990846679999" fill="red" opacity="0"/></g><g class="schematic-port-hover sch-port-hover" data-schematic-port-id="source_port_1_0__stack1"><circle cx="144.16475972567002" cy="454.6338672769" r="5.491990846679999" fill="red" opacity="0"/></g><g class="schematic-port-hover sch-port-hover" data-schematic-port-id="source_port_1_1__stack1"><circle cx="295.19450800937" cy="454.6338672769" r="5.491990846679999" fill="red" opacity="0"/></g><g class="schematic-port-hover sch-port-hover" data-schematic-port-id="source_port_2_0__stack1"><circle cx="952.8604118993001" cy="454.6338672769" r="5.491990846679999" fill="red" opacity="0"/></g><g class="schematic-port-hover sch-port-hover" data-schematic-port-id="source_port_2_1__stack1"><circle cx="952.8604118993001" cy="482.09382151029996" r="5.491990846679999" fill="red" opacity="0"/></g><g class="schematic-port-hover sch-port-hover" data-schematic-port-id="source_port_2_2__stack1"><circle cx="952.8604118993001" cy="509.5537757437" r="5.491990846679999" fill="red" opacity="0"/></g><g class="schematic-port-hover sch-port-hover" data-schematic-port-id="source_port_2_3__stack1"><circle cx="952.8604118993001" cy="537.0137299771" r="5.491990846679999" fill="red" opacity="0"/></g><g class="schematic-port-hover sch-port-hover" data-schematic-port-id="source_port_2_4__stack1"><circle cx="1117.6201372997" cy="537.0137299771" r="5.491990846679999" fill="red" opacity="0"/></g><g class="schematic-port-hover sch-port-hover" data-schematic-port-id="source_port_2_5__stack1"><circle cx="1117.6201372997" cy="509.5537757437" r="5.491990846679999" fill="red" opacity="0"/></g><g class="schematic-port-hover sch-port-hover" data-schematic-port-id="source_port_2_6__stack1"><circle cx="1117.6201372997" cy="482.09382151029996" r="5.491990846679999" fill="red" opacity="0"/></g><g class="schematic-port-hover sch-port-hover" data-schematic-port-id="source_port_2_7__stack1"><circle cx="1117.6201372997" cy="454.6338672769" r="5.491990846679999" fill="red" opacity="0"/></g><g class="schematic-port-hover sch-port-hover" data-schematic-port-id="source_port_3_0__stack1"><circle cx="551.9450800916601" cy="509.5537757437" r="5.491990846679999" fill="red" opacity="0"/></g><g class="schematic-port-hover sch-port-hover" data-schematic-port-id="source_port_3_1__stack1"><circle cx="551.9450800916601" cy="537.0137299771" r="5.491990846679999" fill="red" opacity="0"/></g><g class="schematic-port-hover sch-port-hover" data-schematic-port-id="source_port_3_2__stack1"><circle cx="551.9450800916601" cy="564.4736842105" r="5.491990846679999" fill="red" opacity="0"/></g><g class="schematic-port-hover sch-port-hover" data-schematic-port-id="source_port_3_3__stack1"><circle cx="551.9450800916601" cy="591.9336384439" r="5.491990846679999" fill="red" opacity="0"/></g><g class="schematic-port-hover sch-port-hover" data-schematic-port-id="source_port_3_4__stack1"><circle cx="716.7048054920601" cy="591.9336384439" r="5.491990846679999" fill="red" opacity="0"/></g><g class="schematic-port-hover sch-port-hover" data-schematic-port-id="source_port_3_5__stack1"><circle cx="716.7048054920601" cy="564.4736842105" r="5.491990846679999" fill="red" opacity="0"/></g><g class="schematic-port-hover sch-port-hover" data-schematic-port-id="source_port_3_6__stack1"><circle cx="716.7048054920601" cy="537.0137299771" r="5.491990846679999" fill="red" opacity="0"/></g><g class="schematic-port-hover sch-port-hover" data-schematic-port-id="source_port_3_7__stack1"><circle cx="716.7048054920601" cy="509.5537757437" r="5.491990846679999" fill="red" opacity="0"/></g><path class="net-label sch-net-label" data-circuit-json-type="schematic_net_label" data-schematic-net-label-id="schematic_net_label_0__stack1" d="
90
+ </style><rect class="boundary" x="0" y="0" width="1200" height="800"/><g class="trace sch-trace" data-layer="base" data-circuit-json-type="schematic_trace" data-schematic-trace-id="schematic_trace_0__stack1"><path d="M 109.83981693392002 454.6338672769 L 82.3798627005201 454.6338672769 L 82.3798627005201 262.41418764310004 L 453.08924485142006 262.41418764310004" class="trace-invisible-hover-outline sch-trace-hitbox" stroke="rgb(0, 150, 0)" fill="none" stroke-width="21.967963386719997px" stroke-linecap="round" opacity="0" stroke-linejoin="round"/><path class="sch-trace-path" d="M 109.83981693392002 454.6338672769 L 82.3798627005201 454.6338672769 L 82.3798627005201 262.41418764310004 L 453.08924485142006 262.41418764310004" stroke="rgb(0, 150, 0)" fill="none" stroke-width="2.7459954233399997px" stroke-linecap="round" stroke-linejoin="round"/></g><g class="trace sch-trace" data-layer="base" data-circuit-json-type="schematic_trace" data-schematic-trace-id="schematic_trace_1__stack1"><path d="M 952.8604118993001 454.6338672769 L 260.86956521762 454.6338672769" class="trace-invisible-hover-outline sch-trace-hitbox" stroke="rgb(0, 150, 0)" fill="none" stroke-width="21.967963386719997px" stroke-linecap="round" opacity="0" stroke-linejoin="round"/><path class="sch-trace-path" d="M 952.8604118993001 454.6338672769 L 260.86956521762 454.6338672769" stroke="rgb(0, 150, 0)" fill="none" stroke-width="2.7459954233399997px" stroke-linecap="round" stroke-linejoin="round"/></g><g class="trace sch-trace" data-layer="base" data-circuit-json-type="schematic_trace" data-schematic-trace-id="schematic_trace_2__stack1"><path d="M 551.9450800916601 509.5537757437 L 524.4851258582601 509.5537757437 L 524.4851258582601 468.3638443936 L 877.2082379862829 468.3638443936 L 877.2082379862829 509.5537757437 L 952.8604118993 509.5537757437" class="trace-invisible-hover-outline sch-trace-hitbox" stroke="rgb(0, 150, 0)" fill="none" stroke-width="21.967963386719997px" stroke-linecap="round" opacity="0" stroke-linejoin="round"/><path class="sch-trace-path" d="M 551.9450800916601 509.5537757437 L 524.4851258582601 509.5537757437 L 524.4851258582601 468.3638443936 L 877.2082379862829 468.3638443936 L 877.2082379862829 509.5537757437 L 952.8604118993 509.5537757437" stroke="rgb(0, 150, 0)" fill="none" stroke-width="2.7459954233399997px" stroke-linecap="round" stroke-linejoin="round"/></g><g class="trace sch-trace" data-layer="base" data-circuit-json-type="schematic_trace" data-schematic-trace-id="schematic_trace_3__stack1"><path d="M 952.8604118993001 482.09382151029996 L 925.4004576659 482.09382151029996 L 925.4004576659 262.41418764310004 L 631.5789473685202 262.41418764310004 L 604.11899313512 262.41418764310004" class="trace-invisible-hover-outline sch-trace-hitbox" stroke="rgb(0, 150, 0)" fill="none" stroke-width="21.967963386719997px" stroke-linecap="round" opacity="0" stroke-linejoin="round"/><path class="sch-trace-path" d="M 952.8604118993001 482.09382151029996 L 925.4004576659 482.09382151029996 L 925.4004576659 262.41418764310004 L 631.5789473685202 262.41418764310004 L 604.11899313512 262.41418764310004" stroke="rgb(0, 150, 0)" fill="none" stroke-width="2.7459954233399997px" stroke-linecap="round" stroke-linejoin="round"/></g><g class="trace-overlays sch-trace-overlays" data-layer="overlay" data-circuit-json-type="schematic_trace" data-schematic-trace-id="schematic_trace_0__stack1"/><g class="trace-overlays sch-trace-overlays" data-layer="overlay" data-circuit-json-type="schematic_trace" data-schematic-trace-id="schematic_trace_1__stack1"/><g class="trace-overlays sch-trace-overlays" data-layer="overlay" data-circuit-json-type="schematic_trace" data-schematic-trace-id="schematic_trace_2__stack1"/><g class="trace-overlays sch-trace-overlays" data-layer="overlay" data-circuit-json-type="schematic_trace" data-schematic-trace-id="schematic_trace_3__stack1"/><g class="sch-component" data-circuit-json-type="schematic_component" data-schematic-component-id="schematic_component_0__stack1"><rect class="component-overlay sch-component-overlay" x="453.08924485142" y="242.28192219688282" width="151.02974828370003" height="40.264530892434436" fill="transparent"/><path class="sch-component-symbol-path" d="M 453.08924485142 262.41418764310004 L 478.2659038903128 262.41418764310004" stroke="rgb(132, 0, 0)" fill="none" stroke-width="2.7459954233399997px" stroke-linecap="round"/><path class="sch-component-symbol-path" d="M 578.9423340962273 262.41418764310004 L 604.11899313512 262.41418764310004" stroke="rgb(132, 0, 0)" fill="none" stroke-width="2.7459954233399997px" stroke-linecap="round"/><path class="sch-component-symbol-path" d="M 478.2659038903128 242.28192219688282 L 578.9423340962273 242.28192219688282 L 578.9423340962273 282.54645308931725 L 478.2659038903128 282.54645308931725 L 478.2659038903128 242.28192219688282" stroke="rgb(132, 0, 0)" fill="none" stroke-width="2.7459954233399997px" stroke-linecap="round"/><text class="sch-component-name sch-component-text" x="528.60411899327" y="222.13958810078003" stroke="rgb(245, 241, 237)" stroke-width="2.7459954233399997px" paint-order="stroke" fill="rgb(15, 15, 15)" font-family="sans-serif" text-anchor="middle" dominant-baseline="ideographic" font-size="24.713958810059996px">R1</text><text class="sch-component-text" x="528.60411899327" y="302.68878718542004" fill="rgb(15, 15, 15)" font-family="sans-serif" text-anchor="middle" dominant-baseline="hanging" font-size="24.713958810059996px"></text></g><g class="sch-component" data-circuit-json-type="schematic_component" data-schematic-component-id="schematic_component_1__stack1"><rect class="component-overlay sch-component-overlay" x="109.83981693392003" y="414.35423340963723" width="151.02974828369997" height="80.55926773452552" fill="transparent"/><path class="sch-component-symbol-path" d="M 260.86956521762 454.6338672769 L 200.45766590414 454.6338672769" stroke="rgb(132, 0, 0)" fill="none" stroke-width="2.7459954233399997px" stroke-linecap="round"/><path class="sch-component-symbol-path" d="M 170.25171624740003 454.6338672769 L 109.83981693392003 454.6338672769" stroke="rgb(132, 0, 0)" fill="none" stroke-width="2.7459954233399997px" stroke-linecap="round"/><path class="sch-component-symbol-path" d="M 200.45766590414 414.35423340963723 L 200.45766590414 494.91350114416275" stroke="rgb(132, 0, 0)" fill="none" stroke-width="2.7459954233399997px" stroke-linecap="round"/><path class="sch-component-symbol-path" d="M 170.25171624740003 414.35423340963723 L 170.25171624740003 494.91350114416275" stroke="rgb(132, 0, 0)" fill="none" stroke-width="2.7459954233399997px" stroke-linecap="round"/><text class="sch-component-name sch-component-text" x="185.35469107577" y="394.22196796342" stroke="rgb(245, 241, 237)" stroke-width="2.7459954233399997px" paint-order="stroke" fill="rgb(15, 15, 15)" font-family="sans-serif" text-anchor="middle" dominant-baseline="ideographic" font-size="24.713958810059996px">C1</text><text class="sch-component-text" x="185.35469107577" y="515.0457665903799" fill="rgb(15, 15, 15)" font-family="sans-serif" text-anchor="middle" dominant-baseline="hanging" font-size="24.713958810059996px"></text></g><g class="sch-component" data-circuit-json-type="schematic_component" data-schematic-component-id="schematic_component_2__stack1"><rect class="component chip sch-component-body" x="1007.7803203661" y="427.17391304349997" width="54.91990846679994" height="137.29977116700002" stroke-width="2.7459954233399997px" fill="rgb(255, 255, 194)" stroke="rgb(132, 0, 0)"/><rect class="component-overlay sch-component-overlay" x="1007.7803203661" y="427.17391304349997" width="54.91990846679994" height="137.29977116700002" fill="transparent"/><text class="sch-text" x="1035.2402745995" y="495.823798627" fill="#0f172a" text-anchor="middle" dominant-baseline="middle" font-family="sans-serif" font-size="24.713958810059996px" transform="rotate(0, 1035.2402745995, 495.823798627)">U1</text><line class="component-pin sch-component-pin sch-port-line" x1="1007.7803203661" y1="454.6338672769" x2="952.8604118993001" y2="454.6338672769" stroke-width="2.7459954233399997px"/><g class="sch-port" data-schematic-port-id="source_port_2_0__stack1"><rect x="950.1144164759601" y="451.88787185356" width="5.491990846679999" height="5.491990846679999" opacity="0"/></g><text class="pin-number sch-pin-number" x="980.3203661327" y="451.88787185356" style="font-family: sans-serif;" fill="rgb(169, 0, 0)" text-anchor="middle" dominant-baseline="auto" font-size="20.59496567505px" transform="">1</text><line class="component-pin sch-component-pin sch-port-line" x1="1007.7803203661" y1="482.09382151029996" x2="952.8604118993001" y2="482.09382151029996" stroke-width="2.7459954233399997px"/><g class="sch-port" data-schematic-port-id="source_port_2_1__stack1"><rect x="950.1144164759601" y="479.34782608695997" width="5.491990846679999" height="5.491990846679999" opacity="0"/></g><text class="pin-number sch-pin-number" x="980.3203661327" y="479.34782608695997" style="font-family: sans-serif;" fill="rgb(169, 0, 0)" text-anchor="middle" dominant-baseline="auto" font-size="20.59496567505px" transform="">2</text><line class="component-pin sch-component-pin sch-port-line" x1="1007.7803203661" y1="509.5537757437" x2="952.8604118993001" y2="509.5537757437" stroke-width="2.7459954233399997px"/><g class="sch-port" data-schematic-port-id="source_port_2_2__stack1"><rect x="950.1144164759601" y="506.80778032036" width="5.491990846679999" height="5.491990846679999" opacity="0"/></g><text class="pin-number sch-pin-number" x="980.3203661327" y="506.80778032036" style="font-family: sans-serif;" fill="rgb(169, 0, 0)" text-anchor="middle" dominant-baseline="auto" font-size="20.59496567505px" transform="">3</text><line class="component-pin sch-component-pin sch-port-line" x1="1007.7803203661" y1="537.0137299771" x2="955.60640732264" y2="537.0137299771" stroke-width="2.7459954233399997px"/><g class="sch-port" data-schematic-port-id="source_port_2_3__stack1"><circle class="component-pin sch-component-pin sch-port-terminal" cx="952.8604118993001" cy="537.0137299771" r="2.7459954233399997" stroke-width="2.7459954233399997px"/><rect x="950.1144164759601" y="534.26773455376" width="5.491990846679999" height="5.491990846679999" opacity="0"/></g><text class="pin-number sch-pin-number" x="980.3203661327" y="534.26773455376" style="font-family: sans-serif;" fill="rgb(169, 0, 0)" text-anchor="middle" dominant-baseline="auto" font-size="20.59496567505px" transform="">4</text><line class="component-pin sch-component-pin sch-port-line" x1="1062.7002288329" y1="537.0137299771" x2="1114.87414187636" y2="537.0137299771" stroke-width="2.7459954233399997px"/><g class="sch-port" data-schematic-port-id="source_port_2_4__stack1"><circle class="component-pin sch-component-pin sch-port-terminal" cx="1117.6201372997" cy="537.0137299771" r="2.7459954233399997" stroke-width="2.7459954233399997px"/><rect x="1114.87414187636" y="534.26773455376" width="5.491990846679999" height="5.491990846679999" opacity="0"/></g><text class="pin-number sch-pin-number" x="1090.1601830663" y="534.26773455376" style="font-family: sans-serif;" fill="rgb(169, 0, 0)" text-anchor="middle" dominant-baseline="auto" font-size="20.59496567505px" transform="">5</text><line class="component-pin sch-component-pin sch-port-line" x1="1062.7002288329" y1="509.5537757437" x2="1114.87414187636" y2="509.5537757437" stroke-width="2.7459954233399997px"/><g class="sch-port" data-schematic-port-id="source_port_2_5__stack1"><circle class="component-pin sch-component-pin sch-port-terminal" cx="1117.6201372997" cy="509.5537757437" r="2.7459954233399997" stroke-width="2.7459954233399997px"/><rect x="1114.87414187636" y="506.80778032036" width="5.491990846679999" height="5.491990846679999" opacity="0"/></g><text class="pin-number sch-pin-number" x="1090.1601830663" y="506.80778032036" style="font-family: sans-serif;" fill="rgb(169, 0, 0)" text-anchor="middle" dominant-baseline="auto" font-size="20.59496567505px" transform="">6</text><line class="component-pin sch-component-pin sch-port-line" x1="1062.7002288329" y1="482.09382151029996" x2="1114.87414187636" y2="482.09382151029996" stroke-width="2.7459954233399997px"/><g class="sch-port" data-schematic-port-id="source_port_2_6__stack1"><circle class="component-pin sch-component-pin sch-port-terminal" cx="1117.6201372997" cy="482.09382151029996" r="2.7459954233399997" stroke-width="2.7459954233399997px"/><rect x="1114.87414187636" y="479.34782608695997" width="5.491990846679999" height="5.491990846679999" opacity="0"/></g><text class="pin-number sch-pin-number" x="1090.1601830663" y="479.34782608695997" style="font-family: sans-serif;" fill="rgb(169, 0, 0)" text-anchor="middle" dominant-baseline="auto" font-size="20.59496567505px" transform="">7</text><line class="component-pin sch-component-pin sch-port-line" x1="1062.7002288329" y1="454.6338672769" x2="1114.87414187636" y2="454.6338672769" stroke-width="2.7459954233399997px"/><g class="sch-port" data-schematic-port-id="source_port_2_7__stack1"><circle class="component-pin sch-component-pin sch-port-terminal" cx="1117.6201372997" cy="454.6338672769" r="2.7459954233399997" stroke-width="2.7459954233399997px"/><rect x="1114.87414187636" y="451.88787185356" width="5.491990846679999" height="5.491990846679999" opacity="0"/></g><text class="pin-number sch-pin-number" x="1090.1601830663" y="451.88787185356" style="font-family: sans-serif;" fill="rgb(169, 0, 0)" text-anchor="middle" dominant-baseline="auto" font-size="20.59496567505px" transform="">8</text></g><g class="sch-component" data-circuit-json-type="schematic_component" data-schematic-component-id="schematic_component_3__stack1"><rect class="component chip sch-component-body" x="606.86498855846" y="482.09382151029996" width="54.91990846680005" height="137.29977116699996" stroke-width="2.7459954233399997px" fill="rgb(255, 255, 194)" stroke="rgb(132, 0, 0)"/><rect class="component-overlay sch-component-overlay" x="606.86498855846" y="482.09382151029996" width="54.91990846680005" height="137.29977116699996" fill="transparent"/><text class="sch-text" x="634.32494279186" y="550.7437070937999" fill="#0f172a" text-anchor="middle" dominant-baseline="middle" font-family="sans-serif" font-size="24.713958810059996px" transform="rotate(0, 634.32494279186, 550.7437070937999)">U2</text><line class="component-pin sch-component-pin sch-port-line" x1="606.86498855846" y1="509.5537757437" x2="551.9450800916601" y2="509.5537757437" stroke-width="2.7459954233399997px"/><g class="sch-port" data-schematic-port-id="source_port_3_0__stack1"><rect x="549.1990846683201" y="506.80778032036" width="5.491990846679999" height="5.491990846679999" opacity="0"/></g><text class="pin-number sch-pin-number" x="579.4050343250601" y="506.80778032036" style="font-family: sans-serif;" fill="rgb(169, 0, 0)" text-anchor="middle" dominant-baseline="auto" font-size="20.59496567505px" transform="">1</text><line class="component-pin sch-component-pin sch-port-line" x1="606.86498855846" y1="537.0137299771" x2="554.6910755150001" y2="537.0137299771" stroke-width="2.7459954233399997px"/><g class="sch-port" data-schematic-port-id="source_port_3_1__stack1"><circle class="component-pin sch-component-pin sch-port-terminal" cx="551.9450800916601" cy="537.0137299771" r="2.7459954233399997" stroke-width="2.7459954233399997px"/><rect x="549.1990846683201" y="534.26773455376" width="5.491990846679999" height="5.491990846679999" opacity="0"/></g><text class="pin-number sch-pin-number" x="579.4050343250601" y="534.26773455376" style="font-family: sans-serif;" fill="rgb(169, 0, 0)" text-anchor="middle" dominant-baseline="auto" font-size="20.59496567505px" transform="">2</text><line class="component-pin sch-component-pin sch-port-line" x1="606.86498855846" y1="564.4736842105" x2="554.6910755150001" y2="564.4736842105" stroke-width="2.7459954233399997px"/><g class="sch-port" data-schematic-port-id="source_port_3_2__stack1"><circle class="component-pin sch-component-pin sch-port-terminal" cx="551.9450800916601" cy="564.4736842105" r="2.7459954233399997" stroke-width="2.7459954233399997px"/><rect x="549.1990846683201" y="561.72768878716" width="5.491990846679999" height="5.491990846679999" opacity="0"/></g><text class="pin-number sch-pin-number" x="579.4050343250601" y="561.72768878716" style="font-family: sans-serif;" fill="rgb(169, 0, 0)" text-anchor="middle" dominant-baseline="auto" font-size="20.59496567505px" transform="">3</text><line class="component-pin sch-component-pin sch-port-line" x1="606.86498855846" y1="591.9336384439" x2="554.6910755150001" y2="591.9336384439" stroke-width="2.7459954233399997px"/><g class="sch-port" data-schematic-port-id="source_port_3_3__stack1"><circle class="component-pin sch-component-pin sch-port-terminal" cx="551.9450800916601" cy="591.9336384439" r="2.7459954233399997" stroke-width="2.7459954233399997px"/><rect x="549.1990846683201" y="589.18764302056" width="5.491990846679999" height="5.491990846679999" opacity="0"/></g><text class="pin-number sch-pin-number" x="579.4050343250601" y="589.18764302056" style="font-family: sans-serif;" fill="rgb(169, 0, 0)" text-anchor="middle" dominant-baseline="auto" font-size="20.59496567505px" transform="">4</text><line class="component-pin sch-component-pin sch-port-line" x1="661.7848970252601" y1="591.9336384439" x2="713.9588100687201" y2="591.9336384439" stroke-width="2.7459954233399997px"/><g class="sch-port" data-schematic-port-id="source_port_3_4__stack1"><circle class="component-pin sch-component-pin sch-port-terminal" cx="716.7048054920601" cy="591.9336384439" r="2.7459954233399997" stroke-width="2.7459954233399997px"/><rect x="713.9588100687201" y="589.18764302056" width="5.491990846679999" height="5.491990846679999" opacity="0"/></g><text class="pin-number sch-pin-number" x="689.24485125866" y="589.18764302056" style="font-family: sans-serif;" fill="rgb(169, 0, 0)" text-anchor="middle" dominant-baseline="auto" font-size="20.59496567505px" transform="">5</text><line class="component-pin sch-component-pin sch-port-line" x1="661.7848970252601" y1="564.4736842105" x2="713.9588100687201" y2="564.4736842105" stroke-width="2.7459954233399997px"/><g class="sch-port" data-schematic-port-id="source_port_3_5__stack1"><circle class="component-pin sch-component-pin sch-port-terminal" cx="716.7048054920601" cy="564.4736842105" r="2.7459954233399997" stroke-width="2.7459954233399997px"/><rect x="713.9588100687201" y="561.72768878716" width="5.491990846679999" height="5.491990846679999" opacity="0"/></g><text class="pin-number sch-pin-number" x="689.24485125866" y="561.72768878716" style="font-family: sans-serif;" fill="rgb(169, 0, 0)" text-anchor="middle" dominant-baseline="auto" font-size="20.59496567505px" transform="">6</text><line class="component-pin sch-component-pin sch-port-line" x1="661.7848970252601" y1="537.0137299771" x2="713.9588100687201" y2="537.0137299771" stroke-width="2.7459954233399997px"/><g class="sch-port" data-schematic-port-id="source_port_3_6__stack1"><circle class="component-pin sch-component-pin sch-port-terminal" cx="716.7048054920601" cy="537.0137299771" r="2.7459954233399997" stroke-width="2.7459954233399997px"/><rect x="713.9588100687201" y="534.26773455376" width="5.491990846679999" height="5.491990846679999" opacity="0"/></g><text class="pin-number sch-pin-number" x="689.24485125866" y="534.26773455376" style="font-family: sans-serif;" fill="rgb(169, 0, 0)" text-anchor="middle" dominant-baseline="auto" font-size="20.59496567505px" transform="">7</text><line class="component-pin sch-component-pin sch-port-line" x1="661.7848970252601" y1="509.5537757437" x2="713.9588100687201" y2="509.5537757437" stroke-width="2.7459954233399997px"/><g class="sch-port" data-schematic-port-id="source_port_3_7__stack1"><circle class="component-pin sch-component-pin sch-port-terminal" cx="716.7048054920601" cy="509.5537757437" r="2.7459954233399997" stroke-width="2.7459954233399997px"/><rect x="713.9588100687201" y="506.80778032036" width="5.491990846679999" height="5.491990846679999" opacity="0"/></g><text class="pin-number sch-pin-number" x="689.24485125866" y="506.80778032036" style="font-family: sans-serif;" fill="rgb(169, 0, 0)" text-anchor="middle" dominant-baseline="auto" font-size="20.59496567505px" transform="">8</text></g><g class="schematic-port-hover sch-port-hover" data-schematic-port-id="source_port_0_0__stack1"><circle cx="487.41418764317007" cy="262.41418764310004" r="5.491990846679999" fill="red" opacity="0"/></g><g class="schematic-port-hover sch-port-hover" data-schematic-port-id="source_port_0_1__stack1"><circle cx="638.4439359268702" cy="262.41418764310004" r="5.491990846679999" fill="red" opacity="0"/></g><g class="schematic-port-hover sch-port-hover" data-schematic-port-id="source_port_1_0__stack1"><circle cx="144.16475972567002" cy="454.6338672769" r="5.491990846679999" fill="red" opacity="0"/></g><g class="schematic-port-hover sch-port-hover" data-schematic-port-id="source_port_1_1__stack1"><circle cx="295.19450800937" cy="454.6338672769" r="5.491990846679999" fill="red" opacity="0"/></g><g class="schematic-port-hover sch-port-hover" data-schematic-port-id="source_port_2_0__stack1"><circle cx="952.8604118993001" cy="454.6338672769" r="5.491990846679999" fill="red" opacity="0"/></g><g class="schematic-port-hover sch-port-hover" data-schematic-port-id="source_port_2_1__stack1"><circle cx="952.8604118993001" cy="482.09382151029996" r="5.491990846679999" fill="red" opacity="0"/></g><g class="schematic-port-hover sch-port-hover" data-schematic-port-id="source_port_2_2__stack1"><circle cx="952.8604118993001" cy="509.5537757437" r="5.491990846679999" fill="red" opacity="0"/></g><g class="schematic-port-hover sch-port-hover" data-schematic-port-id="source_port_2_3__stack1"><circle cx="952.8604118993001" cy="537.0137299771" r="5.491990846679999" fill="red" opacity="0"/></g><g class="schematic-port-hover sch-port-hover" data-schematic-port-id="source_port_2_4__stack1"><circle cx="1117.6201372997" cy="537.0137299771" r="5.491990846679999" fill="red" opacity="0"/></g><g class="schematic-port-hover sch-port-hover" data-schematic-port-id="source_port_2_5__stack1"><circle cx="1117.6201372997" cy="509.5537757437" r="5.491990846679999" fill="red" opacity="0"/></g><g class="schematic-port-hover sch-port-hover" data-schematic-port-id="source_port_2_6__stack1"><circle cx="1117.6201372997" cy="482.09382151029996" r="5.491990846679999" fill="red" opacity="0"/></g><g class="schematic-port-hover sch-port-hover" data-schematic-port-id="source_port_2_7__stack1"><circle cx="1117.6201372997" cy="454.6338672769" r="5.491990846679999" fill="red" opacity="0"/></g><g class="schematic-port-hover sch-port-hover" data-schematic-port-id="source_port_3_0__stack1"><circle cx="551.9450800916601" cy="509.5537757437" r="5.491990846679999" fill="red" opacity="0"/></g><g class="schematic-port-hover sch-port-hover" data-schematic-port-id="source_port_3_1__stack1"><circle cx="551.9450800916601" cy="537.0137299771" r="5.491990846679999" fill="red" opacity="0"/></g><g class="schematic-port-hover sch-port-hover" data-schematic-port-id="source_port_3_2__stack1"><circle cx="551.9450800916601" cy="564.4736842105" r="5.491990846679999" fill="red" opacity="0"/></g><g class="schematic-port-hover sch-port-hover" data-schematic-port-id="source_port_3_3__stack1"><circle cx="551.9450800916601" cy="591.9336384439" r="5.491990846679999" fill="red" opacity="0"/></g><g class="schematic-port-hover sch-port-hover" data-schematic-port-id="source_port_3_4__stack1"><circle cx="716.7048054920601" cy="591.9336384439" r="5.491990846679999" fill="red" opacity="0"/></g><g class="schematic-port-hover sch-port-hover" data-schematic-port-id="source_port_3_5__stack1"><circle cx="716.7048054920601" cy="564.4736842105" r="5.491990846679999" fill="red" opacity="0"/></g><g class="schematic-port-hover sch-port-hover" data-schematic-port-id="source_port_3_6__stack1"><circle cx="716.7048054920601" cy="537.0137299771" r="5.491990846679999" fill="red" opacity="0"/></g><g class="schematic-port-hover sch-port-hover" data-schematic-port-id="source_port_3_7__stack1"><circle cx="716.7048054920601" cy="509.5537757437" r="5.491990846679999" fill="red" opacity="0"/></g><path class="net-label sch-net-label" data-circuit-json-type="schematic_net_label" data-schematic-net-label-id="schematic_net_label_0__stack1" d="
91
91
  M 82.3798627005201,454.6338672769
92
92
  L 96.1098398172201,462.048054919918
93
93
  L 96.1098398172201,509.1327231121212
@@ -1,4 +1,5 @@
1
- import { test, expect } from "bun:test"
1
+ import { expect, test } from "bun:test"
2
+ import { countCrossingsWithOtherTraces } from "lib/solvers/Example28Solver/countCrossingsWithOtherTraces"
2
3
  import { SchematicTracePipelineSolver } from "lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver"
3
4
  import inputProblem from "../assets/example37.json"
4
5
  import "tests/fixtures/matcher"
@@ -8,5 +9,16 @@ test("example37", () => {
8
9
 
9
10
  solver.solve()
10
11
 
12
+ const traces = solver.netLabelToTraceSolver!.getOutput().traces
13
+ const recoveredTrace = traces.find(
14
+ (trace) => trace.mspPairId === "net-label-to-trace-R1.2--U1.2",
15
+ )!
16
+
17
+ expect(
18
+ countCrossingsWithOtherTraces({
19
+ trace: recoveredTrace,
20
+ outputTraces: traces,
21
+ }),
22
+ ).toBe(1)
11
23
  expect(solver).toMatchSolverSnapshot(import.meta.path)
12
24
  })