@tscircuit/schematic-trace-solver 0.0.168 → 0.0.169

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.
Files changed (20) hide show
  1. package/dist/index.js +77 -1
  2. package/lib/solvers/NetLabelToTraceSolver/NetLabelToTraceSolver.ts +2 -2
  3. package/lib/solvers/NetLabelTraceRecovery/doesTraceRecoveryPathConflict.ts +112 -0
  4. package/package.json +1 -1
  5. package/tests/bug-reports/bug-report-20260706T213649Z/__snapshots__/bug-report-20260706T213649Z.snap.svg +60 -222
  6. package/tests/bug-reports/bug-report-20260707T141025Z/__snapshots__/bug-report-20260707T141025Z.snap.svg +46 -64
  7. package/tests/bug-reports/bug-report-20260707T141421Z/__snapshots__/bug-report-20260707T141421Z.snap.svg +7 -25
  8. package/tests/bug-reports/bug-report-20260708T095725Z/__snapshots__/bug-report-20260708T095725Z.snap.svg +68 -104
  9. package/tests/examples/__snapshots__/example35.snap.svg +5 -23
  10. package/tests/examples/__snapshots__/example36.snap.svg +27 -45
  11. package/tests/examples/__snapshots__/example37.snap.svg +7 -25
  12. package/tests/examples/__snapshots__/example51.snap.svg +47 -83
  13. package/tests/repros/__snapshots__/board1096-usb-label-overlap-iteration.snap.svg +5 -23
  14. package/tests/repros/__snapshots__/repro-bc107a-common-emitter-routing.snap.svg +141 -0
  15. package/tests/repros/__snapshots__/repro-dc-power-isolated-routing.snap.svg +6 -24
  16. package/tests/repros/__snapshots__/repro-powerbank-3v-system-power.snap.svg +255 -0
  17. package/tests/repros/assets/repro-bc107a-common-emitter-routing.input.json +687 -0
  18. package/tests/repros/assets/repro-powerbank-3v-system-power.input.json +1772 -0
  19. package/tests/repros/repro-bc107a-common-emitter-routing.test.ts +16 -0
  20. package/tests/repros/repro-powerbank-3v-system-power.test.ts +17 -0
package/dist/index.js CHANGED
@@ -15296,6 +15296,82 @@ var getTraceRecoveryConnectivityMaps = (inputProblem) => {
15296
15296
  return { chipMap, pinMap };
15297
15297
  };
15298
15298
 
15299
+ // lib/solvers/NetLabelTraceRecovery/doesTraceRecoveryPathConflict.ts
15300
+ import { doSegmentsIntersect as doSegmentsIntersect4 } from "@tscircuit/math-utils";
15301
+ var EPSILON = 1e-6;
15302
+ var isStrictlyBetween2 = ({
15303
+ coordinate,
15304
+ segmentStartCoordinate,
15305
+ segmentEndCoordinate
15306
+ }) => coordinate > Math.min(segmentStartCoordinate, segmentEndCoordinate) + EPSILON && coordinate < Math.max(segmentStartCoordinate, segmentEndCoordinate) - EPSILON;
15307
+ var isStrictInteriorPerpendicularCrossing = ({
15308
+ firstSegmentStart,
15309
+ firstSegmentEnd,
15310
+ secondSegmentStart,
15311
+ secondSegmentEnd
15312
+ }) => {
15313
+ const firstIsHorizontal = Math.abs(firstSegmentStart.y - firstSegmentEnd.y) <= EPSILON;
15314
+ const firstIsVertical = Math.abs(firstSegmentStart.x - firstSegmentEnd.x) <= EPSILON;
15315
+ const secondIsHorizontal = Math.abs(secondSegmentStart.y - secondSegmentEnd.y) <= EPSILON;
15316
+ const secondIsVertical = Math.abs(secondSegmentStart.x - secondSegmentEnd.x) <= EPSILON;
15317
+ let horizontalStart;
15318
+ let horizontalEnd;
15319
+ if (firstIsHorizontal) {
15320
+ horizontalStart = firstSegmentStart;
15321
+ horizontalEnd = firstSegmentEnd;
15322
+ } else if (secondIsHorizontal) {
15323
+ horizontalStart = secondSegmentStart;
15324
+ horizontalEnd = secondSegmentEnd;
15325
+ } else {
15326
+ return false;
15327
+ }
15328
+ let verticalStart;
15329
+ let verticalEnd;
15330
+ if (firstIsVertical) {
15331
+ verticalStart = firstSegmentStart;
15332
+ verticalEnd = firstSegmentEnd;
15333
+ } else if (secondIsVertical) {
15334
+ verticalStart = secondSegmentStart;
15335
+ verticalEnd = secondSegmentEnd;
15336
+ } else {
15337
+ return false;
15338
+ }
15339
+ return isStrictlyBetween2({
15340
+ coordinate: verticalStart.x,
15341
+ segmentStartCoordinate: horizontalStart.x,
15342
+ segmentEndCoordinate: horizontalEnd.x
15343
+ }) && isStrictlyBetween2({
15344
+ coordinate: horizontalStart.y,
15345
+ segmentStartCoordinate: verticalStart.y,
15346
+ segmentEndCoordinate: verticalEnd.y
15347
+ });
15348
+ };
15349
+ var doesTraceRecoveryPathConflict = (tracePath, collisionTraces) => {
15350
+ for (let pathIndex = 0; pathIndex < tracePath.length - 1; pathIndex++) {
15351
+ const pathStart = tracePath[pathIndex];
15352
+ const pathEnd = tracePath[pathIndex + 1];
15353
+ for (const trace of collisionTraces) {
15354
+ for (let traceIndex = 0; traceIndex < trace.tracePath.length - 1; traceIndex++) {
15355
+ const traceStart = trace.tracePath[traceIndex];
15356
+ const traceEnd = trace.tracePath[traceIndex + 1];
15357
+ if (!doSegmentsIntersect4(pathStart, pathEnd, traceStart, traceEnd)) {
15358
+ continue;
15359
+ }
15360
+ if (isStrictInteriorPerpendicularCrossing({
15361
+ firstSegmentStart: pathStart,
15362
+ firstSegmentEnd: pathEnd,
15363
+ secondSegmentStart: traceStart,
15364
+ secondSegmentEnd: traceEnd
15365
+ })) {
15366
+ continue;
15367
+ }
15368
+ return true;
15369
+ }
15370
+ }
15371
+ }
15372
+ return false;
15373
+ };
15374
+
15299
15375
  // lib/solvers/NetLabelToTraceSolver/NetLabelToTraceSolver.ts
15300
15376
  var AVAILABLE_NET_ORIENTATION_PREFIX = "available-net-orientation-";
15301
15377
  var RECOVERED_TRACE_PREFIX = "net-label-to-trace-";
@@ -15566,7 +15642,7 @@ var NetLabelToTraceSolver = class extends BaseSolver {
15566
15642
  (trace) => trace.globalConnNetId !== candidate.firstLabel.globalConnNetId
15567
15643
  );
15568
15644
  }
15569
- if (doesTraceOverlapWithExistingTraces(tracePath, collisionTraces) || this.routeIntersectsRemainingLabels(tracePath, candidate)) {
15645
+ if (doesTraceRecoveryPathConflict(tracePath, collisionTraces) || this.routeIntersectsRemainingLabels(tracePath, candidate)) {
15570
15646
  return;
15571
15647
  }
15572
15648
  const [firstPin, secondPin] = candidate.pins;
@@ -12,6 +12,7 @@ import {
12
12
  getTraceRecoveryConnectivityMaps,
13
13
  type TraceRecoveryPin,
14
14
  } from "lib/solvers/NetLabelTraceRecovery/getTraceRecoveryConnectivityMaps"
15
+ import { doesTraceRecoveryPathConflict } from "lib/solvers/NetLabelTraceRecovery/doesTraceRecoveryPathConflict"
15
16
  import { getTraceConnectedPinComponents } from "lib/solvers/SchematicTraceLinesSolver/getTraceConnectedPinComponents"
16
17
  import type { SolvedTracePath } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceLinesSolver"
17
18
  import { SchematicTraceSingleLineSolver2 } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/SchematicTraceSingleLineSolver2"
@@ -22,7 +23,6 @@ import type {
22
23
  PinId,
23
24
  } from "lib/types/InputProblem"
24
25
  import { arePinsInDifferentSchematicSections } from "lib/utils/arePinsInDifferentSchematicSections"
25
- import { doesTraceOverlapWithExistingTraces } from "lib/utils/does-trace-overlap-with-existing-traces"
26
26
  import {
27
27
  type InlineNetLabelPlacement,
28
28
  type InlineNetLabelOutput,
@@ -434,7 +434,7 @@ export class NetLabelToTraceSolver extends BaseSolver {
434
434
  )
435
435
  }
436
436
  if (
437
- doesTraceOverlapWithExistingTraces(tracePath, collisionTraces) ||
437
+ doesTraceRecoveryPathConflict(tracePath, collisionTraces) ||
438
438
  this.routeIntersectsRemainingLabels(tracePath, candidate)
439
439
  ) {
440
440
  return
@@ -0,0 +1,112 @@
1
+ import { doSegmentsIntersect, type Point } from "@tscircuit/math-utils"
2
+ import type { SolvedTracePath } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceLinesSolver"
3
+
4
+ const EPSILON = 1e-6
5
+
6
+ const isStrictlyBetween = ({
7
+ coordinate,
8
+ segmentStartCoordinate,
9
+ segmentEndCoordinate,
10
+ }: {
11
+ coordinate: number
12
+ segmentStartCoordinate: number
13
+ segmentEndCoordinate: number
14
+ }) =>
15
+ coordinate >
16
+ Math.min(segmentStartCoordinate, segmentEndCoordinate) + EPSILON &&
17
+ coordinate < Math.max(segmentStartCoordinate, segmentEndCoordinate) - EPSILON
18
+
19
+ const isStrictInteriorPerpendicularCrossing = ({
20
+ firstSegmentStart,
21
+ firstSegmentEnd,
22
+ secondSegmentStart,
23
+ secondSegmentEnd,
24
+ }: {
25
+ firstSegmentStart: Point
26
+ firstSegmentEnd: Point
27
+ secondSegmentStart: Point
28
+ secondSegmentEnd: Point
29
+ }) => {
30
+ const firstIsHorizontal =
31
+ Math.abs(firstSegmentStart.y - firstSegmentEnd.y) <= EPSILON
32
+ const firstIsVertical =
33
+ Math.abs(firstSegmentStart.x - firstSegmentEnd.x) <= EPSILON
34
+ const secondIsHorizontal =
35
+ Math.abs(secondSegmentStart.y - secondSegmentEnd.y) <= EPSILON
36
+ const secondIsVertical =
37
+ Math.abs(secondSegmentStart.x - secondSegmentEnd.x) <= EPSILON
38
+
39
+ let horizontalStart: Point
40
+ let horizontalEnd: Point
41
+ if (firstIsHorizontal) {
42
+ horizontalStart = firstSegmentStart
43
+ horizontalEnd = firstSegmentEnd
44
+ } else if (secondIsHorizontal) {
45
+ horizontalStart = secondSegmentStart
46
+ horizontalEnd = secondSegmentEnd
47
+ } else {
48
+ return false
49
+ }
50
+
51
+ let verticalStart: Point
52
+ let verticalEnd: Point
53
+ if (firstIsVertical) {
54
+ verticalStart = firstSegmentStart
55
+ verticalEnd = firstSegmentEnd
56
+ } else if (secondIsVertical) {
57
+ verticalStart = secondSegmentStart
58
+ verticalEnd = secondSegmentEnd
59
+ } else {
60
+ return false
61
+ }
62
+
63
+ return (
64
+ isStrictlyBetween({
65
+ coordinate: verticalStart.x,
66
+ segmentStartCoordinate: horizontalStart.x,
67
+ segmentEndCoordinate: horizontalEnd.x,
68
+ }) &&
69
+ isStrictlyBetween({
70
+ coordinate: horizontalStart.y,
71
+ segmentStartCoordinate: verticalStart.y,
72
+ segmentEndCoordinate: verticalEnd.y,
73
+ })
74
+ )
75
+ }
76
+
77
+ export const doesTraceRecoveryPathConflict = (
78
+ tracePath: Point[],
79
+ collisionTraces: SolvedTracePath[],
80
+ ) => {
81
+ for (let pathIndex = 0; pathIndex < tracePath.length - 1; pathIndex++) {
82
+ const pathStart = tracePath[pathIndex]!
83
+ const pathEnd = tracePath[pathIndex + 1]!
84
+
85
+ for (const trace of collisionTraces) {
86
+ for (
87
+ let traceIndex = 0;
88
+ traceIndex < trace.tracePath.length - 1;
89
+ traceIndex++
90
+ ) {
91
+ const traceStart = trace.tracePath[traceIndex]!
92
+ const traceEnd = trace.tracePath[traceIndex + 1]!
93
+ if (!doSegmentsIntersect(pathStart, pathEnd, traceStart, traceEnd)) {
94
+ continue
95
+ }
96
+ if (
97
+ isStrictInteriorPerpendicularCrossing({
98
+ firstSegmentStart: pathStart,
99
+ firstSegmentEnd: pathEnd,
100
+ secondSegmentStart: traceStart,
101
+ secondSegmentEnd: traceEnd,
102
+ })
103
+ ) {
104
+ continue
105
+ }
106
+ return true
107
+ }
108
+ }
109
+ }
110
+
111
+ return false
112
+ }
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.168",
8
+ "version": "0.0.169",
9
9
  "type": "module",
10
10
  "scripts": {
11
11
  "start": "cosmos",