@tscircuit/schematic-trace-solver 0.0.203 → 0.0.204
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 +18 -6
- package/lib/solvers/TraceCleanupSolver/sameNetRailAlignment/getFixedLabelCoordinate.ts +17 -8
- package/lib/solvers/TraceElbowTransitionSimplificationSolver/TraceElbowTransitionSimplificationSolver.ts +25 -3
- package/package.json +1 -1
- package/site/SchematicTracePipelineSolver/repro-smart-lock-ble-module.page.tsx +7 -0
- package/tests/bug-reports/bug-report-20260706T213649Z/__snapshots__/bug-report-20260706T213649Z.snap.svg +78 -60
- package/tests/bug-reports/bug-report-20260707T134722Z/__snapshots__/bug-report-20260707T134722Z.snap.svg +62 -62
- package/tests/bug-reports/bug-report-20260708T055430Z/__snapshots__/bug-report-20260708T055430Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260721T221026Z/__snapshots__/bug-report-20260721T221026Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260728T144234Z/__snapshots__/bug-report-20260728T144234Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260901T055358Z/__snapshots__/bug-report-20260901T055358Z.snap.svg +10 -10
- package/tests/bug-reports/bug-report-20260905T041712Z/__snapshots__/bug-report-20260905T041712Z.snap.svg +10 -10
- package/tests/bug-reports/bug-report-20260907T110144Z/__snapshots__/bug-report-20260907T110144Z.snap.svg +9 -9
- package/tests/bug-reports/bug-report-20260907T145640Z/__snapshots__/bug-report-20260907T145640Z.snap.svg +8 -8
- package/tests/bug-reports/bug-report-20260911T195723Z/__snapshots__/bug-report-20260911T195723Z.snap.svg +19 -19
- package/tests/bug-reports/bug-report-20260916T054012Z/__snapshots__/bug-report-20260916T054012Z.snap.svg +292 -292
- package/tests/examples/__snapshots__/example30.snap.svg +123 -123
- package/tests/repros/__snapshots__/board-1273-trace-overlap-cycle.snap.svg +18 -18
- package/tests/repros/__snapshots__/board-15984-same-net-junction.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-am3352-sheet3-power-rails.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-hub-usb-sheet.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-ina237-current-monitor.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-pmp11282-isolated-dcdc.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-robot-controller-imu-tof.snap.svg +7 -7
- package/tests/repros/__snapshots__/repro-smart-lock-ble-module.snap.svg +465 -0
- package/tests/repros/__snapshots__/repro-tida010076-page02.snap.svg +10 -10
- package/tests/repros/assets/repro-smart-lock-ble-module.input.json +2183 -0
- package/tests/repros/repro-smart-lock-ble-module.test.ts +69 -0
- package/tests/solvers/TraceCleanupSolver/alignSameNetRails-fixed-backbone.test.ts +135 -0
- package/tests/solvers/TraceElbowTransitionSimplificationSolver/interior-staircase.test.ts +146 -0
package/dist/index.js
CHANGED
|
@@ -6328,10 +6328,6 @@ var getFixedLabelCoordinate = (group, netLabelPlacements, traces) => {
|
|
|
6328
6328
|
const groupIsWithinSingleComponent = [...groupTraceIds].every(
|
|
6329
6329
|
(traceId) => traceMap.get(traceId)?.pins.every((pin) => pin.chipId === group[0].componentId) === true
|
|
6330
6330
|
);
|
|
6331
|
-
const groupHasOnlySingleRailTraces = [...groupTraceIds].every(
|
|
6332
|
-
(traceId) => traceMap.get(traceId)?.tracePath.length === 4
|
|
6333
|
-
);
|
|
6334
|
-
if (!groupHasOnlySingleRailTraces) return null;
|
|
6335
6331
|
const orientation = group[0].orientation;
|
|
6336
6332
|
const linkedLabels = getLabelsLinkedToRailGroup(
|
|
6337
6333
|
group,
|
|
@@ -6362,6 +6358,11 @@ var getFixedLabelCoordinate = (group, netLabelPlacements, traces) => {
|
|
|
6362
6358
|
const coordinate = group.find(
|
|
6363
6359
|
(segment) => Math.abs(segment.coordinate - labelCoordinate) <= RAIL_ALIGNMENT_EPSILON
|
|
6364
6360
|
)?.coordinate ?? labelCoordinate;
|
|
6361
|
+
if (group.some(
|
|
6362
|
+
(segment) => traceMap.get(segment.traceId)?.tracePath.length !== 4 && !nearlyEqual(segment.coordinate, coordinate)
|
|
6363
|
+
)) {
|
|
6364
|
+
return null;
|
|
6365
|
+
}
|
|
6365
6366
|
const labelIsAnchoredToRoutedBackbone = anchoringLabels.some(
|
|
6366
6367
|
(label) => label.mspConnectionPairIds.some(
|
|
6367
6368
|
(traceId) => (traceMap.get(traceId)?.tracePath.length ?? 0) > 4
|
|
@@ -15505,7 +15506,17 @@ var TraceElbowTransitionSimplificationSolver = class extends BaseSolver {
|
|
|
15505
15506
|
const otherNetTraces = this.outputTraces.filter(
|
|
15506
15507
|
(otherTrace) => otherTrace.mspPairId !== trace.mspPairId && otherTrace.globalConnNetId !== trace.globalConnNetId
|
|
15507
15508
|
);
|
|
15509
|
+
const initialPathLength = getPathLength6(tracePath);
|
|
15508
15510
|
const candidateByPath = /* @__PURE__ */ new Map();
|
|
15511
|
+
for (const candidate of getInteriorShortcutPaths(tracePath)) {
|
|
15512
|
+
if (Math.abs(getPathLength6(candidate) - initialPathLength) > PATH_LENGTH_EPSILON3) {
|
|
15513
|
+
continue;
|
|
15514
|
+
}
|
|
15515
|
+
candidateByPath.set(
|
|
15516
|
+
candidate.map((point) => `${point.x},${point.y}`).join(";"),
|
|
15517
|
+
candidate
|
|
15518
|
+
);
|
|
15519
|
+
}
|
|
15509
15520
|
const completedReroutes = this.input.completedReroutes.filter(
|
|
15510
15521
|
(completedReroute) => completedReroute.initialTrace.mspPairId === trace.mspPairId
|
|
15511
15522
|
);
|
|
@@ -15557,7 +15568,6 @@ var TraceElbowTransitionSimplificationSolver = class extends BaseSolver {
|
|
|
15557
15568
|
({ label }) => `${label.globalConnNetId}:${label.netId}`
|
|
15558
15569
|
)
|
|
15559
15570
|
);
|
|
15560
|
-
const initialPathLength = getPathLength6(tracePath);
|
|
15561
15571
|
const validCandidates = [...candidateByPath.values()].filter(
|
|
15562
15572
|
(candidatePath) => {
|
|
15563
15573
|
const candidateTrace = { ...trace, tracePath: candidatePath };
|
|
@@ -15574,7 +15584,9 @@ var TraceElbowTransitionSimplificationSolver = class extends BaseSolver {
|
|
|
15574
15584
|
this.input.netLabelPlacements,
|
|
15575
15585
|
[trace],
|
|
15576
15586
|
[candidateTrace]
|
|
15577
|
-
) && !isPathCollidingWithObstacles(candidatePath, this.obstacles) && !doesPathCoincideWithTraces(candidatePath, otherNetTraces)
|
|
15587
|
+
) && !isPathCollidingWithObstacles(candidatePath, this.obstacles) && !doesPathCoincideWithTraces(candidatePath, otherNetTraces) && otherNetTraces.every(
|
|
15588
|
+
(otherTrace) => countPathIntersections(candidatePath, otherTrace.tracePath) <= countPathIntersections(tracePath, otherTrace.tracePath)
|
|
15589
|
+
);
|
|
15578
15590
|
}
|
|
15579
15591
|
);
|
|
15580
15592
|
const getOverlapCount = (candidatePath) => detectTraceLabelOverlap({
|
|
@@ -2,7 +2,11 @@ import { distance } from "@tscircuit/math-utils"
|
|
|
2
2
|
import type { NetLabelPlacement } from "lib/solvers/NetLabelPlacementSolver/NetLabelPlacementSolver"
|
|
3
3
|
import { tracePathContainsPoint } from "lib/solvers/RailNetLabelCornerPlacementSolver/geometry"
|
|
4
4
|
import type { SolvedTracePath } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceLinesSolver"
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
getDistinctCoordinates,
|
|
7
|
+
nearlyEqual,
|
|
8
|
+
RAIL_ALIGNMENT_EPSILON,
|
|
9
|
+
} from "./geometry"
|
|
6
10
|
import type { RailSegment } from "./types"
|
|
7
11
|
|
|
8
12
|
const getTransitivelyConnectedTraceIds = (
|
|
@@ -59,13 +63,6 @@ export const getFixedLabelCoordinate = (
|
|
|
59
63
|
.get(traceId)
|
|
60
64
|
?.pins.every((pin) => pin.chipId === group[0]!.componentId) === true,
|
|
61
65
|
)
|
|
62
|
-
const groupHasOnlySingleRailTraces = [...groupTraceIds].every(
|
|
63
|
-
(traceId) => traceMap.get(traceId)?.tracePath.length === 4,
|
|
64
|
-
)
|
|
65
|
-
// A fixed label may lengthen the endpoint legs around one movable rail. A
|
|
66
|
-
// trace with more elbows still has to pass the normal readability scoring.
|
|
67
|
-
if (!groupHasOnlySingleRailTraces) return null
|
|
68
|
-
|
|
69
66
|
const orientation = group[0]!.orientation
|
|
70
67
|
const linkedLabels = getLabelsLinkedToRailGroup(
|
|
71
68
|
group,
|
|
@@ -107,6 +104,18 @@ export const getFixedLabelCoordinate = (
|
|
|
107
104
|
Math.abs(segment.coordinate - labelCoordinate) <=
|
|
108
105
|
RAIL_ALIGNMENT_EPSILON,
|
|
109
106
|
)?.coordinate ?? labelCoordinate
|
|
107
|
+
// A fixed label may lengthen the endpoint legs around one movable rail.
|
|
108
|
+
// A multi-turn backbone may share the group when it already lies on that
|
|
109
|
+
// coordinate, but moving its elbows still requires normal readability scoring.
|
|
110
|
+
if (
|
|
111
|
+
group.some(
|
|
112
|
+
(segment) =>
|
|
113
|
+
traceMap.get(segment.traceId)?.tracePath.length !== 4 &&
|
|
114
|
+
!nearlyEqual(segment.coordinate, coordinate),
|
|
115
|
+
)
|
|
116
|
+
) {
|
|
117
|
+
return null
|
|
118
|
+
}
|
|
110
119
|
const labelIsAnchoredToRoutedBackbone = anchoringLabels.some((label) =>
|
|
111
120
|
label.mspConnectionPairIds.some(
|
|
112
121
|
(traceId) => (traceMap.get(traceId)?.tracePath.length ?? 0) > 4,
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import type { Point } from "@tscircuit/math-utils"
|
|
2
2
|
import type { GraphicsObject } from "graphics-debug"
|
|
3
3
|
import { BaseSolver } from "lib/solvers/BaseSolver/BaseSolver"
|
|
4
|
+
import { countPathIntersections } from "lib/solvers/Example28Solver/geometry"
|
|
4
5
|
import type { NetLabelPlacement } from "lib/solvers/NetLabelPlacementSolver/NetLabelPlacementSolver"
|
|
5
6
|
import type { SolvedTracePath } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceLinesSolver"
|
|
6
7
|
import { isPathCollidingWithObstacles } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/collisions"
|
|
7
8
|
import { getObstacleRects } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/rect"
|
|
8
9
|
import { visualizeInputProblem } from "lib/solvers/SchematicTracePipelineSolver/visualizeInputProblem"
|
|
10
|
+
import { getInteriorShortcutPaths } from "lib/solvers/TraceCleanupSolver/getInteriorShortcutPaths"
|
|
9
11
|
import { preservesLabelAnchors } from "lib/solvers/TraceCleanupSolver/sameNetRailAlignment/preservesLabelAnchors"
|
|
10
12
|
import { simplifyPath } from "lib/solvers/TraceCleanupSolver/simplifyPath"
|
|
11
13
|
import { detectTraceLabelOverlap } from "lib/solvers/TraceLabelOverlapAvoidanceSolver/detectTraceLabelOverlap"
|
|
@@ -82,7 +84,24 @@ export class TraceElbowTransitionSimplificationSolver extends BaseSolver {
|
|
|
82
84
|
otherTrace.mspPairId !== trace.mspPairId &&
|
|
83
85
|
otherTrace.globalConnNetId !== trace.globalConnNetId,
|
|
84
86
|
)
|
|
87
|
+
const initialPathLength = getPathLength(tracePath)
|
|
85
88
|
const candidateByPath = new Map<string, Point[]>()
|
|
89
|
+
// Consecutive label detours can leave a staircase between two clear legs.
|
|
90
|
+
// Keep equivalent-length shortcuts, as with the transition candidates below;
|
|
91
|
+
// shortening the route belongs to turn minimization. Terminal directions,
|
|
92
|
+
// label anchors, and collision checks still apply.
|
|
93
|
+
for (const candidate of getInteriorShortcutPaths(tracePath)) {
|
|
94
|
+
if (
|
|
95
|
+
Math.abs(getPathLength(candidate) - initialPathLength) >
|
|
96
|
+
PATH_LENGTH_EPSILON
|
|
97
|
+
) {
|
|
98
|
+
continue
|
|
99
|
+
}
|
|
100
|
+
candidateByPath.set(
|
|
101
|
+
candidate.map((point) => `${point.x},${point.y}`).join(";"),
|
|
102
|
+
candidate,
|
|
103
|
+
)
|
|
104
|
+
}
|
|
86
105
|
const completedReroutes = this.input.completedReroutes.filter(
|
|
87
106
|
(completedReroute) =>
|
|
88
107
|
completedReroute.initialTrace.mspPairId === trace.mspPairId,
|
|
@@ -145,8 +164,6 @@ export class TraceElbowTransitionSimplificationSolver extends BaseSolver {
|
|
|
145
164
|
({ label }) => `${label.globalConnNetId}:${label.netId}`,
|
|
146
165
|
),
|
|
147
166
|
)
|
|
148
|
-
const initialPathLength = getPathLength(tracePath)
|
|
149
|
-
|
|
150
167
|
const validCandidates = [...candidateByPath.values()].filter(
|
|
151
168
|
(candidatePath) => {
|
|
152
169
|
const candidateTrace = { ...trace, tracePath: candidatePath }
|
|
@@ -175,7 +192,12 @@ export class TraceElbowTransitionSimplificationSolver extends BaseSolver {
|
|
|
175
192
|
[candidateTrace],
|
|
176
193
|
) &&
|
|
177
194
|
!isPathCollidingWithObstacles(candidatePath, this.obstacles) &&
|
|
178
|
-
!doesPathCoincideWithTraces(candidatePath, otherNetTraces)
|
|
195
|
+
!doesPathCoincideWithTraces(candidatePath, otherNetTraces) &&
|
|
196
|
+
otherNetTraces.every(
|
|
197
|
+
(otherTrace) =>
|
|
198
|
+
countPathIntersections(candidatePath, otherTrace.tracePath) <=
|
|
199
|
+
countPathIntersections(tracePath, otherTrace.tracePath),
|
|
200
|
+
)
|
|
179
201
|
)
|
|
180
202
|
},
|
|
181
203
|
)
|
package/package.json
CHANGED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { InputProblem } from "lib/types/InputProblem"
|
|
2
|
+
import { PipelineDebugger } from "site/components/PipelineDebugger"
|
|
3
|
+
import input from "../../tests/repros/assets/repro-smart-lock-ble-module.input.json"
|
|
4
|
+
|
|
5
|
+
export default () => (
|
|
6
|
+
<PipelineDebugger inputProblem={input as unknown as InputProblem} />
|
|
7
|
+
)
|