@tscircuit/schematic-trace-solver 0.0.202 → 0.0.203
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 +36 -1
- package/lib/solvers/TraceCleanupSolver/getInteriorShortcutPaths.ts +41 -0
- package/lib/solvers/TraceCleanupSolver/rerouteGeneratedNetLabelConnectorCrossings.ts +7 -0
- package/package.json +1 -1
- package/tests/repros/__snapshots__/repro-am3352-06-boot.snap.svg +448 -0
- package/tests/repros/assets/repro-am3352-06-boot.input.json +1875 -0
- package/tests/repros/repro-am3352-06-boot.test.ts +43 -0
- package/tests/solvers/TraceCleanupSolver/reroute-generated-net-label-connector-crossings.test.ts +49 -0
package/dist/index.js
CHANGED
|
@@ -7810,6 +7810,36 @@ var is4PointRectangle = (path) => {
|
|
|
7810
7810
|
return isHVHC || isVHVC;
|
|
7811
7811
|
};
|
|
7812
7812
|
|
|
7813
|
+
// lib/solvers/TraceCleanupSolver/getInteriorShortcutPaths.ts
|
|
7814
|
+
var getInteriorShortcutPaths = (path) => {
|
|
7815
|
+
const candidates = [path];
|
|
7816
|
+
for (let startIndex = 1; startIndex < path.length - 3; startIndex++) {
|
|
7817
|
+
for (let endIndex = startIndex + 2; endIndex < path.length - 1; endIndex++) {
|
|
7818
|
+
for (const connection of tryConnectPoints(
|
|
7819
|
+
path[startIndex],
|
|
7820
|
+
path[endIndex]
|
|
7821
|
+
)) {
|
|
7822
|
+
const candidate = simplifyPath([
|
|
7823
|
+
...path.slice(0, startIndex),
|
|
7824
|
+
...connection,
|
|
7825
|
+
...path.slice(endIndex + 1)
|
|
7826
|
+
]);
|
|
7827
|
+
const preservesTerminalDirections = [
|
|
7828
|
+
[0, 1],
|
|
7829
|
+
[-1, -2]
|
|
7830
|
+
].every(([endIndex2, neighborIndex]) => {
|
|
7831
|
+
const endpoint = path.at(endIndex2);
|
|
7832
|
+
const neighbor = path.at(neighborIndex);
|
|
7833
|
+
const candidateNeighbor = candidate.at(neighborIndex);
|
|
7834
|
+
return (neighbor.x - endpoint.x) * (candidateNeighbor.x - endpoint.x) + (neighbor.y - endpoint.y) * (candidateNeighbor.y - endpoint.y) > 0;
|
|
7835
|
+
});
|
|
7836
|
+
if (preservesTerminalDirections) candidates.push(candidate);
|
|
7837
|
+
}
|
|
7838
|
+
}
|
|
7839
|
+
}
|
|
7840
|
+
return candidates;
|
|
7841
|
+
};
|
|
7842
|
+
|
|
7813
7843
|
// lib/solvers/TraceCleanupSolver/rerouteGeneratedNetLabelConnectorCrossings.ts
|
|
7814
7844
|
var EPS13 = 1e-6;
|
|
7815
7845
|
var getConnectorObstacleBounds = (connector, segmentIndex, labels) => {
|
|
@@ -7902,7 +7932,12 @@ var rerouteGeneratedNetLabelConnectorCrossings = ({
|
|
|
7902
7932
|
obstacleBounds,
|
|
7903
7933
|
chipBounds: [],
|
|
7904
7934
|
clearance
|
|
7905
|
-
}).
|
|
7935
|
+
}).flatMap(
|
|
7936
|
+
(candidate) => getInteriorShortcutPaths(candidate.path).map((path) => ({
|
|
7937
|
+
...candidate,
|
|
7938
|
+
path
|
|
7939
|
+
}))
|
|
7940
|
+
).filter(
|
|
7906
7941
|
(candidate) => getPathLength4(candidate.path) <= getPathLength4(trace.tracePath) + EPS13 && countTurns(candidate.path) <= countTurns(trace.tracePath) + 2 && !isPathCollidingWithObstacles(
|
|
7907
7942
|
candidate.path,
|
|
7908
7943
|
componentAndTextObstacles
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { Point } from "@tscircuit/math-utils"
|
|
2
|
+
import { simplifyPath } from "./simplifyPath"
|
|
3
|
+
import { tryConnectPoints } from "./tryConnectPoints"
|
|
4
|
+
|
|
5
|
+
export const getInteriorShortcutPaths = (path: Point[]): Point[][] => {
|
|
6
|
+
const candidates: Point[][] = [path]
|
|
7
|
+
// Reconnect interior points to remove old loops left behind by a connector detour.
|
|
8
|
+
for (let startIndex = 1; startIndex < path.length - 3; startIndex++) {
|
|
9
|
+
for (
|
|
10
|
+
let endIndex = startIndex + 2;
|
|
11
|
+
endIndex < path.length - 1;
|
|
12
|
+
endIndex++
|
|
13
|
+
) {
|
|
14
|
+
for (const connection of tryConnectPoints(
|
|
15
|
+
path[startIndex]!,
|
|
16
|
+
path[endIndex]!,
|
|
17
|
+
)) {
|
|
18
|
+
const candidate = simplifyPath([
|
|
19
|
+
...path.slice(0, startIndex),
|
|
20
|
+
...connection,
|
|
21
|
+
...path.slice(endIndex + 1),
|
|
22
|
+
])
|
|
23
|
+
const preservesTerminalDirections = [
|
|
24
|
+
[0, 1],
|
|
25
|
+
[-1, -2],
|
|
26
|
+
].every(([endIndex, neighborIndex]) => {
|
|
27
|
+
const endpoint = path.at(endIndex!)!
|
|
28
|
+
const neighbor = path.at(neighborIndex!)!
|
|
29
|
+
const candidateNeighbor = candidate.at(neighborIndex!)!
|
|
30
|
+
return (
|
|
31
|
+
(neighbor.x - endpoint.x) * (candidateNeighbor.x - endpoint.x) +
|
|
32
|
+
(neighbor.y - endpoint.y) * (candidateNeighbor.y - endpoint.y) >
|
|
33
|
+
0
|
|
34
|
+
)
|
|
35
|
+
})
|
|
36
|
+
if (preservesTerminalDirections) candidates.push(candidate)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return candidates
|
|
41
|
+
}
|
|
@@ -9,6 +9,7 @@ import { getObstacleRects } from "lib/solvers/SchematicTraceLinesSolver/Schemati
|
|
|
9
9
|
import type { InputProblem } from "lib/types/InputProblem"
|
|
10
10
|
import { doesPathCoincideWithTraces } from "lib/utils/doesPathCoincideWithTraces"
|
|
11
11
|
import { countTurns } from "./countTurns"
|
|
12
|
+
import { getInteriorShortcutPaths } from "./getInteriorShortcutPaths"
|
|
12
13
|
import { hasCollisionsWithLabels } from "./hasCollisionsWithLabels"
|
|
13
14
|
import { findPerpendicularPathCrossings } from "./sub-solver/findIntersectionsWithObstacles"
|
|
14
15
|
import { generatePerpendicularTraceDetours } from "./sub-solver/generateLShapeRerouteCandidates"
|
|
@@ -150,6 +151,12 @@ export const rerouteGeneratedNetLabelConnectorCrossings = ({
|
|
|
150
151
|
chipBounds: [],
|
|
151
152
|
clearance,
|
|
152
153
|
})
|
|
154
|
+
.flatMap((candidate) =>
|
|
155
|
+
getInteriorShortcutPaths(candidate.path).map((path) => ({
|
|
156
|
+
...candidate,
|
|
157
|
+
path,
|
|
158
|
+
})),
|
|
159
|
+
)
|
|
153
160
|
.filter(
|
|
154
161
|
(candidate) =>
|
|
155
162
|
getPathLength(candidate.path) <=
|