@tscircuit/schematic-trace-solver 0.0.93 → 0.0.94

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
@@ -5653,6 +5653,30 @@ var getSegmentOverlapWithRectSpan = (start, end, rect) => {
5653
5653
 
5654
5654
  // lib/solvers/Example28Solver/reroute.ts
5655
5655
  var LABEL_CLEARANCE = 0.1;
5656
+ var MAX_CORRIDOR_SHIFTS = 16;
5657
+ var corridorHasOtherNetTrace = ({
5658
+ x,
5659
+ lowY,
5660
+ highY,
5661
+ outputTraces,
5662
+ netId
5663
+ }) => {
5664
+ for (const other of outputTraces) {
5665
+ if (other.globalConnNetId === netId) continue;
5666
+ const path = other.tracePath;
5667
+ for (let i = 0; i + 1 < path.length; i++) {
5668
+ const start = path[i];
5669
+ const end = path[i + 1];
5670
+ if (Math.abs(start.x - end.x) >= 1e-9) continue;
5671
+ if (Math.abs(start.x - x) >= LABEL_CLEARANCE / 2) continue;
5672
+ const segLowY = Math.min(start.y, end.y);
5673
+ const segHighY = Math.max(start.y, end.y);
5674
+ if (Math.min(highY, segHighY) - Math.max(lowY, segLowY) > 1e-6)
5675
+ return true;
5676
+ }
5677
+ }
5678
+ return false;
5679
+ };
5656
5680
  var findBestReroutePath = ({
5657
5681
  trace,
5658
5682
  obstacleLabel,
@@ -5691,8 +5715,11 @@ var generateRerouteCandidateResults = ({
5691
5715
  const seen = /* @__PURE__ */ new Set();
5692
5716
  const candidateResults = [];
5693
5717
  const horizontalSegmentPushCandidate = generateHorizontalSegmentPushCandidate(
5694
- trace,
5695
- label
5718
+ {
5719
+ trace,
5720
+ label,
5721
+ outputTraces
5722
+ }
5696
5723
  );
5697
5724
  if (horizontalSegmentPushCandidate) {
5698
5725
  candidateResults.push(
@@ -5886,7 +5913,11 @@ var selectBestReroutePath = ({
5886
5913
  }
5887
5914
  return bestPath;
5888
5915
  };
5889
- var generateHorizontalSegmentPushCandidate = (trace, label) => {
5916
+ var generateHorizontalSegmentPushCandidate = ({
5917
+ trace,
5918
+ label,
5919
+ outputTraces
5920
+ }) => {
5890
5921
  const labelDirection = dir(label.orientation);
5891
5922
  if (labelDirection.x === 0) return null;
5892
5923
  const path = trace.tracePath;
@@ -5911,6 +5942,20 @@ var generateHorizontalSegmentPushCandidate = (trace, label) => {
5911
5942
  if (labelDirection.x > 0) {
5912
5943
  segmentPushX = bounds.maxX + LABEL_CLEARANCE;
5913
5944
  }
5945
+ const corridorStep = labelDirection.x > 0 ? LABEL_CLEARANCE : -LABEL_CLEARANCE;
5946
+ const verticalLowY = Math.min(verticalStart.y, verticalEnd.y);
5947
+ const verticalHighY = Math.max(verticalStart.y, verticalEnd.y);
5948
+ for (let shift = 0; shift < MAX_CORRIDOR_SHIFTS; shift++) {
5949
+ const occupied = corridorHasOtherNetTrace({
5950
+ x: segmentPushX,
5951
+ lowY: verticalLowY,
5952
+ highY: verticalHighY,
5953
+ outputTraces,
5954
+ netId: trace.globalConnNetId
5955
+ });
5956
+ if (!occupied) break;
5957
+ segmentPushX += corridorStep;
5958
+ }
5914
5959
  const segmentPushStartY = getClearedHorizontalY({
5915
5960
  start: previousAnchor,
5916
5961
  end: { x: segmentPushX, y: verticalStart.y },
@@ -8,13 +8,13 @@ import { detectTraceLabelOverlap } from "lib/solvers/TraceLabelOverlapAvoidanceS
8
8
  import { generateRerouteCandidates } from "lib/solvers/TraceLabelOverlapAvoidanceSolver/rerouteCollidingTrace"
9
9
  import type { InputProblem } from "lib/types/InputProblem"
10
10
  import { dir } from "lib/utils/dir"
11
+ import { getChipBoundaryOverlap } from "./doesPathRunAlongChipBoundary"
11
12
  import {
12
13
  countPathIntersections,
13
14
  getPathKey,
14
15
  getPathLength,
15
16
  isPathCollidingWithChipInterior,
16
17
  } from "./geometry"
17
- import { getChipBoundaryOverlap } from "./doesPathRunAlongChipBoundary"
18
18
  import type {
19
19
  ChipObstacle,
20
20
  RerouteCandidateResult,
@@ -22,6 +22,43 @@ import type {
22
22
  } from "./types"
23
23
 
24
24
  const LABEL_CLEARANCE = 0.1
25
+ // How many LABEL_CLEARANCE-wide corridors to try before giving up on finding a
26
+ // free one for a pushed segment.
27
+ const MAX_CORRIDOR_SHIFTS = 16
28
+
29
+ /**
30
+ * Whether a vertical trace segment of a different net already runs along the
31
+ * corridor at `x`, overlapping the [lowY, highY] span (within a corridor width).
32
+ */
33
+ const corridorHasOtherNetTrace = ({
34
+ x,
35
+ lowY,
36
+ highY,
37
+ outputTraces,
38
+ netId,
39
+ }: {
40
+ x: number
41
+ lowY: number
42
+ highY: number
43
+ outputTraces: SolvedTracePath[]
44
+ netId: string
45
+ }): boolean => {
46
+ for (const other of outputTraces) {
47
+ if (other.globalConnNetId === netId) continue
48
+ const path = other.tracePath
49
+ for (let i = 0; i + 1 < path.length; i++) {
50
+ const start = path[i]!
51
+ const end = path[i + 1]!
52
+ if (Math.abs(start.x - end.x) >= 1e-9) continue
53
+ if (Math.abs(start.x - x) >= LABEL_CLEARANCE / 2) continue
54
+ const segLowY = Math.min(start.y, end.y)
55
+ const segHighY = Math.max(start.y, end.y)
56
+ if (Math.min(highY, segHighY) - Math.max(lowY, segLowY) > 1e-6)
57
+ return true
58
+ }
59
+ }
60
+ return false
61
+ }
25
62
 
26
63
  export const findBestReroutePath = ({
27
64
  trace,
@@ -78,8 +115,11 @@ export const generateRerouteCandidateResults = ({
78
115
  const seen = new Set<string>()
79
116
  const candidateResults: RerouteCandidateResult[] = []
80
117
  const horizontalSegmentPushCandidate = generateHorizontalSegmentPushCandidate(
81
- trace,
82
- label,
118
+ {
119
+ trace,
120
+ label,
121
+ outputTraces,
122
+ },
83
123
  )
84
124
 
85
125
  if (horizontalSegmentPushCandidate) {
@@ -328,10 +368,15 @@ const selectBestReroutePath = ({
328
368
  return bestPath
329
369
  }
330
370
 
331
- const generateHorizontalSegmentPushCandidate = (
332
- trace: SolvedTracePath,
333
- label: NetLabelPlacement,
334
- ): Point[] | null => {
371
+ const generateHorizontalSegmentPushCandidate = ({
372
+ trace,
373
+ label,
374
+ outputTraces,
375
+ }: {
376
+ trace: SolvedTracePath
377
+ label: NetLabelPlacement
378
+ outputTraces: SolvedTracePath[]
379
+ }): Point[] | null => {
335
380
  const labelDirection = dir(label.orientation)
336
381
  if (labelDirection.x === 0) return null
337
382
 
@@ -367,6 +412,25 @@ const generateHorizontalSegmentPushCandidate = (
367
412
  if (labelDirection.x > 0) {
368
413
  segmentPushX = bounds.maxX + LABEL_CLEARANCE
369
414
  }
415
+
416
+ // Two traces escaping the same label block would otherwise be pushed to the
417
+ // identical corridor and stack on one line. Slide the corridor further out
418
+ // until it no longer coincides with a different-net trace already routed
419
+ // there, giving each escaping trace its own parallel corridor.
420
+ const corridorStep = labelDirection.x > 0 ? LABEL_CLEARANCE : -LABEL_CLEARANCE
421
+ const verticalLowY = Math.min(verticalStart.y, verticalEnd.y)
422
+ const verticalHighY = Math.max(verticalStart.y, verticalEnd.y)
423
+ for (let shift = 0; shift < MAX_CORRIDOR_SHIFTS; shift++) {
424
+ const occupied = corridorHasOtherNetTrace({
425
+ x: segmentPushX,
426
+ lowY: verticalLowY,
427
+ highY: verticalHighY,
428
+ outputTraces,
429
+ netId: trace.globalConnNetId,
430
+ })
431
+ if (!occupied) break
432
+ segmentPushX += corridorStep
433
+ }
370
434
  const segmentPushStartY = getClearedHorizontalY({
371
435
  start: previousAnchor,
372
436
  end: { x: segmentPushX, y: verticalStart.y },
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tscircuit/schematic-trace-solver",
3
3
  "main": "dist/index.js",
4
- "version": "0.0.93",
4
+ "version": "0.0.94",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "start": "cosmos",