@tscircuit/schematic-trace-solver 0.0.38 → 0.0.40
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.d.ts +1 -2
- package/dist/index.js +64 -62
- package/lib/solvers/TraceLabelOverlapAvoidanceSolver/TraceLabelOverlapAvoidanceSolver.ts +28 -33
- package/lib/solvers/TraceLabelOverlapAvoidanceSolver/hasCollisions.ts +1 -5
- package/lib/solvers/TraceLabelOverlapAvoidanceSolver/hasCollisionsWithLabels.ts +19 -0
- package/lib/solvers/TraceLabelOverlapAvoidanceSolver/minimizeTurnsWithFilteredLabels.ts +66 -0
- package/lib/solvers/TraceLabelOverlapAvoidanceSolver/tryConnectPoints.ts +14 -0
- package/lib/solvers/TraceLabelOverlapAvoidanceSolver/turnMinimization.ts +3 -97
- package/package.json +1 -1
- package/tests/examples/__snapshots__/example27.snap.svg +281 -0
- package/tests/examples/example27.test.ts +241 -0
package/dist/index.d.ts
CHANGED
|
@@ -392,14 +392,13 @@ declare class TraceLabelOverlapAvoidanceSolver extends BaseSolver {
|
|
|
392
392
|
private netTempLabelPlacements;
|
|
393
393
|
private netLabelPlacements;
|
|
394
394
|
private updatedTraces;
|
|
395
|
-
private updatedTracesMap;
|
|
396
395
|
private mergedLabelNetIdMap;
|
|
397
396
|
private detourCountByLabel;
|
|
398
397
|
private readonly PADDING_BUFFER;
|
|
399
398
|
constructor(solverInput: TraceLabelOverlapAvoidanceSolverInput);
|
|
400
399
|
_step(): void;
|
|
401
400
|
getOutput(): {
|
|
402
|
-
|
|
401
|
+
traces: SolvedTracePath[];
|
|
403
402
|
netLabelPlacements: NetLabelPlacement[];
|
|
404
403
|
};
|
|
405
404
|
visualize(): GraphicsObject;
|
package/dist/index.js
CHANGED
|
@@ -1015,12 +1015,12 @@ var applyJogToTerminalSegment = ({
|
|
|
1015
1015
|
if (si !== 0 && si !== pts.length - 2) return;
|
|
1016
1016
|
const start = pts[si];
|
|
1017
1017
|
const end = pts[si + 1];
|
|
1018
|
-
const
|
|
1019
|
-
const
|
|
1020
|
-
if (!
|
|
1021
|
-
const segDir =
|
|
1018
|
+
const isVertical2 = Math.abs(start.x - end.x) < EPS4;
|
|
1019
|
+
const isHorizontal2 = Math.abs(start.y - end.y) < EPS4;
|
|
1020
|
+
if (!isVertical2 && !isHorizontal2) return;
|
|
1021
|
+
const segDir = isVertical2 ? end.y > start.y ? 1 : -1 : end.x > start.x ? 1 : -1;
|
|
1022
1022
|
if (si === 0) {
|
|
1023
|
-
if (
|
|
1023
|
+
if (isVertical2) {
|
|
1024
1024
|
const jogY = start.y + segDir * JOG_SIZE;
|
|
1025
1025
|
pts.splice(
|
|
1026
1026
|
1,
|
|
@@ -1040,7 +1040,7 @@ var applyJogToTerminalSegment = ({
|
|
|
1040
1040
|
);
|
|
1041
1041
|
}
|
|
1042
1042
|
} else {
|
|
1043
|
-
if (
|
|
1043
|
+
if (isVertical2) {
|
|
1044
1044
|
const jogY = end.y - segDir * JOG_SIZE;
|
|
1045
1045
|
pts.splice(
|
|
1046
1046
|
si,
|
|
@@ -1120,10 +1120,10 @@ var TraceOverlapIssueSolver = class extends BaseSolver {
|
|
|
1120
1120
|
} else {
|
|
1121
1121
|
const start = pts[si];
|
|
1122
1122
|
const end = pts[si + 1];
|
|
1123
|
-
const
|
|
1124
|
-
const
|
|
1125
|
-
if (!
|
|
1126
|
-
if (
|
|
1123
|
+
const isVertical2 = Math.abs(start.x - end.x) < EPS4;
|
|
1124
|
+
const isHorizontal2 = Math.abs(start.y - end.y) < EPS4;
|
|
1125
|
+
if (!isVertical2 && !isHorizontal2) continue;
|
|
1126
|
+
if (isVertical2) {
|
|
1127
1127
|
start.x += offset;
|
|
1128
1128
|
end.x += offset;
|
|
1129
1129
|
} else {
|
|
@@ -2508,6 +2508,32 @@ var countTurns = (points) => {
|
|
|
2508
2508
|
return turns;
|
|
2509
2509
|
};
|
|
2510
2510
|
|
|
2511
|
+
// lib/solvers/TraceLabelOverlapAvoidanceSolver/tryConnectPoints.ts
|
|
2512
|
+
var tryConnectPoints = (start, end) => {
|
|
2513
|
+
const candidates = [];
|
|
2514
|
+
if (start.x === end.x || start.y === end.y) {
|
|
2515
|
+
candidates.push([start, end]);
|
|
2516
|
+
} else {
|
|
2517
|
+
candidates.push([start, { x: end.x, y: start.y }, end]);
|
|
2518
|
+
candidates.push([start, { x: start.x, y: end.y }, end]);
|
|
2519
|
+
}
|
|
2520
|
+
return candidates;
|
|
2521
|
+
};
|
|
2522
|
+
|
|
2523
|
+
// lib/solvers/TraceLabelOverlapAvoidanceSolver/hasCollisionsWithLabels.ts
|
|
2524
|
+
var hasCollisionsWithLabels = (pathSegments, labels) => {
|
|
2525
|
+
for (let i = 0; i < pathSegments.length - 1; i++) {
|
|
2526
|
+
const p1 = pathSegments[i];
|
|
2527
|
+
const p2 = pathSegments[i + 1];
|
|
2528
|
+
for (const label of labels) {
|
|
2529
|
+
if (segmentIntersectsRect(p1, p2, label)) {
|
|
2530
|
+
return true;
|
|
2531
|
+
}
|
|
2532
|
+
}
|
|
2533
|
+
}
|
|
2534
|
+
return false;
|
|
2535
|
+
};
|
|
2536
|
+
|
|
2511
2537
|
// lib/solvers/TraceLabelOverlapAvoidanceSolver/turnMinimization.ts
|
|
2512
2538
|
var minimizeTurns = ({
|
|
2513
2539
|
path,
|
|
@@ -2517,28 +2543,6 @@ var minimizeTurns = ({
|
|
|
2517
2543
|
if (path.length <= 2) {
|
|
2518
2544
|
return path;
|
|
2519
2545
|
}
|
|
2520
|
-
const hasCollisionsWithLabels = (pathSegments, labels) => {
|
|
2521
|
-
for (let i = 0; i < pathSegments.length - 1; i++) {
|
|
2522
|
-
const p1 = pathSegments[i];
|
|
2523
|
-
const p2 = pathSegments[i + 1];
|
|
2524
|
-
for (const label of labels) {
|
|
2525
|
-
if (segmentIntersectsRect(p1, p2, label)) {
|
|
2526
|
-
return true;
|
|
2527
|
-
}
|
|
2528
|
-
}
|
|
2529
|
-
}
|
|
2530
|
-
return false;
|
|
2531
|
-
};
|
|
2532
|
-
const tryConnectPoints = (start, end) => {
|
|
2533
|
-
const candidates = [];
|
|
2534
|
-
if (start.x === end.x || start.y === end.y) {
|
|
2535
|
-
candidates.push([start, end]);
|
|
2536
|
-
} else {
|
|
2537
|
-
candidates.push([start, { x: end.x, y: start.y }, end]);
|
|
2538
|
-
candidates.push([start, { x: start.x, y: end.y }, end]);
|
|
2539
|
-
}
|
|
2540
|
-
return candidates;
|
|
2541
|
-
};
|
|
2542
2546
|
const recognizeStairStepPattern = (pathToCheck, startIdx) => {
|
|
2543
2547
|
if (startIdx >= pathToCheck.length - 3) return -1;
|
|
2544
2548
|
let endIdx = startIdx;
|
|
@@ -2672,6 +2676,8 @@ var minimizeTurns = ({
|
|
|
2672
2676
|
const finalSimplifiedPath = simplifyPath(optimizedPath);
|
|
2673
2677
|
return finalSimplifiedPath;
|
|
2674
2678
|
};
|
|
2679
|
+
|
|
2680
|
+
// lib/solvers/TraceLabelOverlapAvoidanceSolver/minimizeTurnsWithFilteredLabels.ts
|
|
2675
2681
|
var minimizeTurnsWithFilteredLabels = ({
|
|
2676
2682
|
traces,
|
|
2677
2683
|
problem,
|
|
@@ -2684,7 +2690,7 @@ var minimizeTurnsWithFilteredLabels = ({
|
|
|
2684
2690
|
const newTraces = traces.map((trace) => {
|
|
2685
2691
|
const originalPath = trace.tracePath;
|
|
2686
2692
|
const filteredLabels = allLabelPlacements.filter((label) => {
|
|
2687
|
-
const originalNetIds = mergedLabelNetIdMap
|
|
2693
|
+
const originalNetIds = mergedLabelNetIdMap[label.globalConnNetId];
|
|
2688
2694
|
if (originalNetIds) {
|
|
2689
2695
|
return !originalNetIds.has(trace.globalConnNetId);
|
|
2690
2696
|
}
|
|
@@ -2865,7 +2871,6 @@ var TraceLabelOverlapAvoidanceSolver = class extends BaseSolver {
|
|
|
2865
2871
|
netTempLabelPlacements;
|
|
2866
2872
|
netLabelPlacements;
|
|
2867
2873
|
updatedTraces;
|
|
2868
|
-
updatedTracesMap;
|
|
2869
2874
|
mergedLabelNetIdMap;
|
|
2870
2875
|
detourCountByLabel;
|
|
2871
2876
|
PADDING_BUFFER = 0.1;
|
|
@@ -2874,28 +2879,27 @@ var TraceLabelOverlapAvoidanceSolver = class extends BaseSolver {
|
|
|
2874
2879
|
this.problem = solverInput.inputProblem;
|
|
2875
2880
|
this.traces = solverInput.traces;
|
|
2876
2881
|
this.updatedTraces = [...solverInput.traces];
|
|
2877
|
-
this.
|
|
2878
|
-
this.
|
|
2879
|
-
this.detourCountByLabel = /* @__PURE__ */ new Map();
|
|
2882
|
+
this.mergedLabelNetIdMap = {};
|
|
2883
|
+
this.detourCountByLabel = {};
|
|
2880
2884
|
const originalLabels = solverInput.netLabelPlacements;
|
|
2881
2885
|
this.netLabelPlacements = originalLabels;
|
|
2882
2886
|
if (!originalLabels || originalLabels.length === 0) {
|
|
2883
2887
|
this.netTempLabelPlacements = [];
|
|
2884
2888
|
return;
|
|
2885
2889
|
}
|
|
2886
|
-
const labelGroups =
|
|
2890
|
+
const labelGroups = {};
|
|
2887
2891
|
for (const p of originalLabels) {
|
|
2888
2892
|
if (p.pinIds.length === 0) continue;
|
|
2889
2893
|
const chipId = p.pinIds[0].split(".")[0];
|
|
2890
2894
|
if (!chipId) continue;
|
|
2891
2895
|
const key = `${chipId}-${p.orientation}`;
|
|
2892
|
-
if (!
|
|
2893
|
-
labelGroups
|
|
2896
|
+
if (!(key in labelGroups)) {
|
|
2897
|
+
labelGroups[key] = [];
|
|
2894
2898
|
}
|
|
2895
|
-
labelGroups
|
|
2899
|
+
labelGroups[key].push(p);
|
|
2896
2900
|
}
|
|
2897
2901
|
const finalPlacements = [];
|
|
2898
|
-
for (const [key, group] of
|
|
2902
|
+
for (const [key, group] of Object.entries(labelGroups)) {
|
|
2899
2903
|
if (group.length <= 1) {
|
|
2900
2904
|
finalPlacements.push(...group);
|
|
2901
2905
|
continue;
|
|
@@ -2913,7 +2917,7 @@ var TraceLabelOverlapAvoidanceSolver = class extends BaseSolver {
|
|
|
2913
2917
|
const template = group[0];
|
|
2914
2918
|
const syntheticId = `merged-group-${key}`;
|
|
2915
2919
|
const originalNetIds = new Set(group.map((p) => p.globalConnNetId));
|
|
2916
|
-
this.mergedLabelNetIdMap
|
|
2920
|
+
this.mergedLabelNetIdMap[syntheticId] = originalNetIds;
|
|
2917
2921
|
finalPlacements.push({
|
|
2918
2922
|
...template,
|
|
2919
2923
|
globalConnNetId: syntheticId,
|
|
@@ -2933,7 +2937,7 @@ var TraceLabelOverlapAvoidanceSolver = class extends BaseSolver {
|
|
|
2933
2937
|
this.solved = true;
|
|
2934
2938
|
return;
|
|
2935
2939
|
}
|
|
2936
|
-
this.detourCountByLabel
|
|
2940
|
+
this.detourCountByLabel = {};
|
|
2937
2941
|
const overlaps = detectTraceLabelOverlap(
|
|
2938
2942
|
this.traces,
|
|
2939
2943
|
this.netTempLabelPlacements
|
|
@@ -2943,9 +2947,7 @@ var TraceLabelOverlapAvoidanceSolver = class extends BaseSolver {
|
|
|
2943
2947
|
return;
|
|
2944
2948
|
}
|
|
2945
2949
|
const unfriendlyOverlaps = overlaps.filter((o) => {
|
|
2946
|
-
const originalNetIds = this.mergedLabelNetIdMap.
|
|
2947
|
-
o.label.globalConnNetId
|
|
2948
|
-
);
|
|
2950
|
+
const originalNetIds = this.mergedLabelNetIdMap[o.label.globalConnNetId];
|
|
2949
2951
|
if (originalNetIds) {
|
|
2950
2952
|
return !originalNetIds.has(o.trace.globalConnNetId);
|
|
2951
2953
|
}
|
|
@@ -2955,18 +2957,18 @@ var TraceLabelOverlapAvoidanceSolver = class extends BaseSolver {
|
|
|
2955
2957
|
this.solved = true;
|
|
2956
2958
|
return;
|
|
2957
2959
|
}
|
|
2958
|
-
const updatedTracesMap =
|
|
2960
|
+
const updatedTracesMap = {};
|
|
2959
2961
|
for (const trace of this.traces) {
|
|
2960
|
-
updatedTracesMap
|
|
2962
|
+
updatedTracesMap[trace.mspPairId] = trace;
|
|
2961
2963
|
}
|
|
2962
2964
|
const processedTraceIds = /* @__PURE__ */ new Set();
|
|
2963
2965
|
for (const overlap of unfriendlyOverlaps) {
|
|
2964
2966
|
if (processedTraceIds.has(overlap.trace.mspPairId)) {
|
|
2965
2967
|
continue;
|
|
2966
2968
|
}
|
|
2967
|
-
const currentTraceState = updatedTracesMap
|
|
2969
|
+
const currentTraceState = updatedTracesMap[overlap.trace.mspPairId];
|
|
2968
2970
|
const labelId = overlap.label.globalConnNetId;
|
|
2969
|
-
const detourCount = this.detourCountByLabel
|
|
2971
|
+
const detourCount = this.detourCountByLabel[labelId] || 0;
|
|
2970
2972
|
const newTrace = rerouteCollidingTrace({
|
|
2971
2973
|
trace: currentTraceState,
|
|
2972
2974
|
label: overlap.label,
|
|
@@ -2975,12 +2977,12 @@ var TraceLabelOverlapAvoidanceSolver = class extends BaseSolver {
|
|
|
2975
2977
|
detourCount
|
|
2976
2978
|
});
|
|
2977
2979
|
if (newTrace.tracePath !== currentTraceState.tracePath) {
|
|
2978
|
-
this.detourCountByLabel
|
|
2980
|
+
this.detourCountByLabel[labelId] = detourCount + 1;
|
|
2979
2981
|
}
|
|
2980
|
-
updatedTracesMap
|
|
2982
|
+
updatedTracesMap[currentTraceState.mspPairId] = newTrace;
|
|
2981
2983
|
processedTraceIds.add(currentTraceState.mspPairId);
|
|
2982
2984
|
}
|
|
2983
|
-
this.updatedTraces =
|
|
2985
|
+
this.updatedTraces = Object.values(updatedTracesMap);
|
|
2984
2986
|
const minimizedTraces = minimizeTurnsWithFilteredLabels({
|
|
2985
2987
|
traces: this.updatedTraces,
|
|
2986
2988
|
problem: this.problem,
|
|
@@ -3000,21 +3002,21 @@ var TraceLabelOverlapAvoidanceSolver = class extends BaseSolver {
|
|
|
3000
3002
|
if (balancedTraces) {
|
|
3001
3003
|
this.updatedTraces = balancedTraces;
|
|
3002
3004
|
}
|
|
3003
|
-
this.updatedTracesMap.clear();
|
|
3004
|
-
for (const trace of this.updatedTraces) {
|
|
3005
|
-
this.updatedTracesMap.set(trace.mspPairId, trace);
|
|
3006
|
-
}
|
|
3007
3005
|
const finalLabelPlacementSolver = new NetLabelPlacementSolver({
|
|
3008
3006
|
inputProblem: this.problem,
|
|
3009
|
-
inputTraceMap: Object.fromEntries(
|
|
3007
|
+
inputTraceMap: Object.fromEntries(
|
|
3008
|
+
this.updatedTraces.map((trace) => [trace.mspPairId, trace])
|
|
3009
|
+
)
|
|
3010
3010
|
});
|
|
3011
3011
|
finalLabelPlacementSolver.solve();
|
|
3012
|
-
|
|
3012
|
+
if (!finalLabelPlacementSolver.failed) {
|
|
3013
|
+
this.netLabelPlacements = finalLabelPlacementSolver.netLabelPlacements;
|
|
3014
|
+
}
|
|
3013
3015
|
this.solved = true;
|
|
3014
3016
|
}
|
|
3015
3017
|
getOutput() {
|
|
3016
3018
|
return {
|
|
3017
|
-
|
|
3019
|
+
traces: this.updatedTraces,
|
|
3018
3020
|
netLabelPlacements: this.netLabelPlacements
|
|
3019
3021
|
};
|
|
3020
3022
|
}
|
|
@@ -3024,7 +3026,7 @@ var TraceLabelOverlapAvoidanceSolver = class extends BaseSolver {
|
|
|
3024
3026
|
if (!graphics.circles) graphics.circles = [];
|
|
3025
3027
|
if (!graphics.texts) graphics.texts = [];
|
|
3026
3028
|
if (!graphics.rects) graphics.rects = [];
|
|
3027
|
-
for (const trace of
|
|
3029
|
+
for (const trace of this.updatedTraces) {
|
|
3028
3030
|
graphics.lines.push({
|
|
3029
3031
|
points: trace.tracePath,
|
|
3030
3032
|
strokeColor: "purple"
|
|
@@ -8,7 +8,7 @@ import { visualizeInputProblem } from "../SchematicTracePipelineSolver/visualize
|
|
|
8
8
|
import { getRectBounds } from "../NetLabelPlacementSolver/SingleNetLabelPlacementSolver/geometry"
|
|
9
9
|
import { getColorFromString } from "lib/utils/getColorFromString"
|
|
10
10
|
import type { InputProblem } from "lib/types/InputProblem"
|
|
11
|
-
import { minimizeTurnsWithFilteredLabels } from "./
|
|
11
|
+
import { minimizeTurnsWithFilteredLabels } from "./minimizeTurnsWithFilteredLabels"
|
|
12
12
|
import { balanceLShapes } from "./balanceLShapes"
|
|
13
13
|
import { NetLabelPlacementSolver } from "../NetLabelPlacementSolver/NetLabelPlacementSolver"
|
|
14
14
|
|
|
@@ -24,9 +24,8 @@ export class TraceLabelOverlapAvoidanceSolver extends BaseSolver {
|
|
|
24
24
|
private netTempLabelPlacements: NetLabelPlacement[]
|
|
25
25
|
private netLabelPlacements: NetLabelPlacement[]
|
|
26
26
|
private updatedTraces: SolvedTracePath[]
|
|
27
|
-
private
|
|
28
|
-
private
|
|
29
|
-
private detourCountByLabel: Map<string, number>
|
|
27
|
+
private mergedLabelNetIdMap: Record<string, Set<string>>
|
|
28
|
+
private detourCountByLabel: Record<string, number>
|
|
30
29
|
private readonly PADDING_BUFFER = 0.1
|
|
31
30
|
|
|
32
31
|
constructor(solverInput: TraceLabelOverlapAvoidanceSolverInput) {
|
|
@@ -34,9 +33,8 @@ export class TraceLabelOverlapAvoidanceSolver extends BaseSolver {
|
|
|
34
33
|
this.problem = solverInput.inputProblem
|
|
35
34
|
this.traces = solverInput.traces
|
|
36
35
|
this.updatedTraces = [...solverInput.traces]
|
|
37
|
-
this.
|
|
38
|
-
this.
|
|
39
|
-
this.detourCountByLabel = new Map()
|
|
36
|
+
this.mergedLabelNetIdMap = {}
|
|
37
|
+
this.detourCountByLabel = {}
|
|
40
38
|
|
|
41
39
|
const originalLabels = solverInput.netLabelPlacements
|
|
42
40
|
this.netLabelPlacements = originalLabels
|
|
@@ -45,21 +43,21 @@ export class TraceLabelOverlapAvoidanceSolver extends BaseSolver {
|
|
|
45
43
|
return
|
|
46
44
|
}
|
|
47
45
|
|
|
48
|
-
const labelGroups
|
|
46
|
+
const labelGroups: Record<string, NetLabelPlacement[]> = {}
|
|
49
47
|
|
|
50
48
|
for (const p of originalLabels) {
|
|
51
49
|
if (p.pinIds.length === 0) continue
|
|
52
50
|
const chipId = p.pinIds[0].split(".")[0]
|
|
53
51
|
if (!chipId) continue
|
|
54
52
|
const key = `${chipId}-${p.orientation}`
|
|
55
|
-
if (!
|
|
56
|
-
labelGroups
|
|
53
|
+
if (!(key in labelGroups)) {
|
|
54
|
+
labelGroups[key] = []
|
|
57
55
|
}
|
|
58
|
-
labelGroups
|
|
56
|
+
labelGroups[key]!.push(p)
|
|
59
57
|
}
|
|
60
58
|
|
|
61
59
|
const finalPlacements: NetLabelPlacement[] = []
|
|
62
|
-
for (const [key, group] of
|
|
60
|
+
for (const [key, group] of Object.entries(labelGroups)) {
|
|
63
61
|
if (group.length <= 1) {
|
|
64
62
|
finalPlacements.push(...group)
|
|
65
63
|
continue
|
|
@@ -82,7 +80,7 @@ export class TraceLabelOverlapAvoidanceSolver extends BaseSolver {
|
|
|
82
80
|
const template = group[0]!
|
|
83
81
|
const syntheticId = `merged-group-${key}`
|
|
84
82
|
const originalNetIds = new Set(group.map((p) => p.globalConnNetId))
|
|
85
|
-
this.mergedLabelNetIdMap
|
|
83
|
+
this.mergedLabelNetIdMap[syntheticId] = originalNetIds
|
|
86
84
|
|
|
87
85
|
finalPlacements.push({
|
|
88
86
|
...template,
|
|
@@ -111,7 +109,7 @@ export class TraceLabelOverlapAvoidanceSolver extends BaseSolver {
|
|
|
111
109
|
return
|
|
112
110
|
}
|
|
113
111
|
|
|
114
|
-
this.detourCountByLabel
|
|
112
|
+
this.detourCountByLabel = {}
|
|
115
113
|
|
|
116
114
|
const overlaps = detectTraceLabelOverlap(
|
|
117
115
|
this.traces,
|
|
@@ -124,9 +122,7 @@ export class TraceLabelOverlapAvoidanceSolver extends BaseSolver {
|
|
|
124
122
|
}
|
|
125
123
|
|
|
126
124
|
const unfriendlyOverlaps = overlaps.filter((o) => {
|
|
127
|
-
const originalNetIds = this.mergedLabelNetIdMap.
|
|
128
|
-
o.label.globalConnNetId,
|
|
129
|
-
)
|
|
125
|
+
const originalNetIds = this.mergedLabelNetIdMap[o.label.globalConnNetId]
|
|
130
126
|
if (originalNetIds) {
|
|
131
127
|
return !originalNetIds.has(o.trace.globalConnNetId)
|
|
132
128
|
}
|
|
@@ -138,9 +134,9 @@ export class TraceLabelOverlapAvoidanceSolver extends BaseSolver {
|
|
|
138
134
|
return
|
|
139
135
|
}
|
|
140
136
|
|
|
141
|
-
const updatedTracesMap
|
|
137
|
+
const updatedTracesMap: Record<string, SolvedTracePath> = {}
|
|
142
138
|
for (const trace of this.traces) {
|
|
143
|
-
updatedTracesMap
|
|
139
|
+
updatedTracesMap[trace.mspPairId] = trace
|
|
144
140
|
}
|
|
145
141
|
|
|
146
142
|
const processedTraceIds = new Set<string>()
|
|
@@ -150,9 +146,9 @@ export class TraceLabelOverlapAvoidanceSolver extends BaseSolver {
|
|
|
150
146
|
continue
|
|
151
147
|
}
|
|
152
148
|
|
|
153
|
-
const currentTraceState = updatedTracesMap
|
|
149
|
+
const currentTraceState = updatedTracesMap[overlap.trace.mspPairId]!
|
|
154
150
|
const labelId = overlap.label.globalConnNetId
|
|
155
|
-
const detourCount = this.detourCountByLabel
|
|
151
|
+
const detourCount = this.detourCountByLabel[labelId] || 0
|
|
156
152
|
|
|
157
153
|
const newTrace = rerouteCollidingTrace({
|
|
158
154
|
trace: currentTraceState,
|
|
@@ -163,14 +159,14 @@ export class TraceLabelOverlapAvoidanceSolver extends BaseSolver {
|
|
|
163
159
|
})
|
|
164
160
|
|
|
165
161
|
if (newTrace.tracePath !== currentTraceState.tracePath) {
|
|
166
|
-
this.detourCountByLabel
|
|
162
|
+
this.detourCountByLabel[labelId] = detourCount + 1
|
|
167
163
|
}
|
|
168
164
|
|
|
169
|
-
updatedTracesMap
|
|
165
|
+
updatedTracesMap[currentTraceState.mspPairId] = newTrace
|
|
170
166
|
processedTraceIds.add(currentTraceState.mspPairId)
|
|
171
167
|
}
|
|
172
168
|
|
|
173
|
-
this.updatedTraces =
|
|
169
|
+
this.updatedTraces = Object.values(updatedTracesMap)
|
|
174
170
|
|
|
175
171
|
const minimizedTraces = minimizeTurnsWithFilteredLabels({
|
|
176
172
|
traces: this.updatedTraces,
|
|
@@ -191,24 +187,23 @@ export class TraceLabelOverlapAvoidanceSolver extends BaseSolver {
|
|
|
191
187
|
this.updatedTraces = balancedTraces
|
|
192
188
|
}
|
|
193
189
|
|
|
194
|
-
this.updatedTracesMap.clear()
|
|
195
|
-
for (const trace of this.updatedTraces) {
|
|
196
|
-
this.updatedTracesMap.set(trace.mspPairId, trace)
|
|
197
|
-
}
|
|
198
|
-
|
|
199
190
|
const finalLabelPlacementSolver = new NetLabelPlacementSolver({
|
|
200
191
|
inputProblem: this.problem,
|
|
201
|
-
inputTraceMap: Object.fromEntries(
|
|
192
|
+
inputTraceMap: Object.fromEntries(
|
|
193
|
+
this.updatedTraces.map((trace) => [trace.mspPairId, trace]),
|
|
194
|
+
),
|
|
202
195
|
})
|
|
203
196
|
finalLabelPlacementSolver.solve()
|
|
204
|
-
|
|
197
|
+
if (!finalLabelPlacementSolver.failed) {
|
|
198
|
+
this.netLabelPlacements = finalLabelPlacementSolver.netLabelPlacements
|
|
199
|
+
}
|
|
205
200
|
|
|
206
201
|
this.solved = true
|
|
207
202
|
}
|
|
208
203
|
|
|
209
204
|
getOutput() {
|
|
210
205
|
return {
|
|
211
|
-
|
|
206
|
+
traces: this.updatedTraces,
|
|
212
207
|
netLabelPlacements: this.netLabelPlacements,
|
|
213
208
|
}
|
|
214
209
|
}
|
|
@@ -221,7 +216,7 @@ export class TraceLabelOverlapAvoidanceSolver extends BaseSolver {
|
|
|
221
216
|
if (!graphics.texts) graphics.texts = []
|
|
222
217
|
if (!graphics.rects) graphics.rects = []
|
|
223
218
|
|
|
224
|
-
for (const trace of
|
|
219
|
+
for (const trace of this.updatedTraces) {
|
|
225
220
|
graphics.lines!.push({
|
|
226
221
|
points: trace.tracePath,
|
|
227
222
|
strokeColor: "purple",
|
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
import type { Point } from "graphics-debug"
|
|
2
|
-
import {
|
|
3
|
-
isVertical,
|
|
4
|
-
isHorizontal,
|
|
5
|
-
segmentIntersectsRect,
|
|
6
|
-
} from "../SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/collisions"
|
|
2
|
+
import { segmentIntersectsRect } from "../SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/collisions"
|
|
7
3
|
|
|
8
4
|
export const hasCollisions = (
|
|
9
5
|
pathSegments: Point[],
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Point } from "@tscircuit/math-utils"
|
|
2
|
+
import { segmentIntersectsRect } from "../SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/collisions"
|
|
3
|
+
|
|
4
|
+
export const hasCollisionsWithLabels = (
|
|
5
|
+
pathSegments: Point[],
|
|
6
|
+
labels: any[],
|
|
7
|
+
): boolean => {
|
|
8
|
+
for (let i = 0; i < pathSegments.length - 1; i++) {
|
|
9
|
+
const p1 = pathSegments[i]
|
|
10
|
+
const p2 = pathSegments[i + 1]
|
|
11
|
+
|
|
12
|
+
for (const label of labels) {
|
|
13
|
+
if (segmentIntersectsRect(p1, p2, label)) {
|
|
14
|
+
return true
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return false
|
|
19
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { InputProblem } from "lib/types/InputProblem"
|
|
2
|
+
import type { NetLabelPlacement } from "../NetLabelPlacementSolver/NetLabelPlacementSolver"
|
|
3
|
+
import type { SolvedTracePath } from "../SchematicTraceLinesSolver/SchematicTraceLinesSolver"
|
|
4
|
+
import { getObstacleRects } from "../SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/rect"
|
|
5
|
+
import { minimizeTurns } from "./turnMinimization"
|
|
6
|
+
|
|
7
|
+
export const minimizeTurnsWithFilteredLabels = ({
|
|
8
|
+
traces,
|
|
9
|
+
problem,
|
|
10
|
+
allLabelPlacements,
|
|
11
|
+
mergedLabelNetIdMap,
|
|
12
|
+
paddingBuffer,
|
|
13
|
+
}: {
|
|
14
|
+
traces: SolvedTracePath[]
|
|
15
|
+
problem: InputProblem
|
|
16
|
+
allLabelPlacements: NetLabelPlacement[]
|
|
17
|
+
mergedLabelNetIdMap: Record<string, Set<string>>
|
|
18
|
+
paddingBuffer: number
|
|
19
|
+
}): SolvedTracePath[] | null => {
|
|
20
|
+
let changesMade = false
|
|
21
|
+
const obstacles = getObstacleRects(problem)
|
|
22
|
+
|
|
23
|
+
const newTraces = traces.map((trace) => {
|
|
24
|
+
const originalPath = trace.tracePath
|
|
25
|
+
const filteredLabels = allLabelPlacements.filter((label) => {
|
|
26
|
+
const originalNetIds = mergedLabelNetIdMap[label.globalConnNetId]
|
|
27
|
+
if (originalNetIds) {
|
|
28
|
+
return !originalNetIds.has(trace.globalConnNetId)
|
|
29
|
+
}
|
|
30
|
+
return label.globalConnNetId !== trace.globalConnNetId
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
const labelBounds = filteredLabels.map((nl) => ({
|
|
34
|
+
minX: nl.center.x - nl.width / 2 - paddingBuffer,
|
|
35
|
+
maxX: nl.center.x + nl.width / 2 + paddingBuffer,
|
|
36
|
+
minY: nl.center.y - nl.height / 2 - paddingBuffer,
|
|
37
|
+
maxY: nl.center.y + nl.height / 2 + paddingBuffer,
|
|
38
|
+
}))
|
|
39
|
+
|
|
40
|
+
const newPath = minimizeTurns({
|
|
41
|
+
path: originalPath,
|
|
42
|
+
obstacles,
|
|
43
|
+
labelBounds,
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
if (
|
|
47
|
+
newPath.length !== originalPath.length ||
|
|
48
|
+
newPath.some(
|
|
49
|
+
(p, i) => p.x !== originalPath[i].x || p.y !== originalPath[i].y,
|
|
50
|
+
)
|
|
51
|
+
) {
|
|
52
|
+
changesMade = true
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return {
|
|
56
|
+
...trace,
|
|
57
|
+
tracePath: newPath,
|
|
58
|
+
}
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
if (changesMade) {
|
|
62
|
+
return newTraces
|
|
63
|
+
} else {
|
|
64
|
+
return null
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Point } from "@tscircuit/math-utils"
|
|
2
|
+
|
|
3
|
+
export const tryConnectPoints = (start: Point, end: Point): Point[][] => {
|
|
4
|
+
const candidates: Point[][] = []
|
|
5
|
+
|
|
6
|
+
if (start.x === end.x || start.y === end.y) {
|
|
7
|
+
candidates.push([start, end])
|
|
8
|
+
} else {
|
|
9
|
+
candidates.push([start, { x: end.x, y: start.y }, end])
|
|
10
|
+
candidates.push([start, { x: start.x, y: end.y }, end])
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return candidates
|
|
14
|
+
}
|
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
import type { Point } from "graphics-debug"
|
|
2
|
-
import type { InputProblem } from "lib/types/InputProblem"
|
|
3
|
-
import type { NetLabelPlacement } from "../NetLabelPlacementSolver/NetLabelPlacementSolver"
|
|
4
|
-
import { getObstacleRects } from "../SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/rect"
|
|
5
|
-
import type { SolvedTracePath } from "../SchematicTraceLinesSolver/SchematicTraceLinesSolver"
|
|
6
|
-
import { segmentIntersectsRect } from "../SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/collisions"
|
|
7
2
|
import { hasCollisions } from "./hasCollisions"
|
|
8
3
|
import { countTurns } from "./countTurns"
|
|
9
4
|
import { simplifyPath } from "./simplifyPath"
|
|
5
|
+
import { tryConnectPoints } from "./tryConnectPoints"
|
|
6
|
+
import { hasCollisionsWithLabels } from "./hasCollisionsWithLabels"
|
|
10
7
|
|
|
11
|
-
const minimizeTurns = ({
|
|
8
|
+
export const minimizeTurns = ({
|
|
12
9
|
path,
|
|
13
10
|
obstacles,
|
|
14
11
|
labelBounds,
|
|
@@ -21,36 +18,6 @@ const minimizeTurns = ({
|
|
|
21
18
|
return path
|
|
22
19
|
}
|
|
23
20
|
|
|
24
|
-
const hasCollisionsWithLabels = (
|
|
25
|
-
pathSegments: Point[],
|
|
26
|
-
labels: any[],
|
|
27
|
-
): boolean => {
|
|
28
|
-
for (let i = 0; i < pathSegments.length - 1; i++) {
|
|
29
|
-
const p1 = pathSegments[i]
|
|
30
|
-
const p2 = pathSegments[i + 1]
|
|
31
|
-
|
|
32
|
-
for (const label of labels) {
|
|
33
|
-
if (segmentIntersectsRect(p1, p2, label)) {
|
|
34
|
-
return true
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
return false
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const tryConnectPoints = (start: Point, end: Point): Point[][] => {
|
|
42
|
-
const candidates: Point[][] = []
|
|
43
|
-
|
|
44
|
-
if (start.x === end.x || start.y === end.y) {
|
|
45
|
-
candidates.push([start, end])
|
|
46
|
-
} else {
|
|
47
|
-
candidates.push([start, { x: end.x, y: start.y }, end])
|
|
48
|
-
candidates.push([start, { x: start.x, y: end.y }, end])
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
return candidates
|
|
52
|
-
}
|
|
53
|
-
|
|
54
21
|
const recognizeStairStepPattern = (
|
|
55
22
|
pathToCheck: Point[],
|
|
56
23
|
startIdx: number,
|
|
@@ -242,64 +209,3 @@ const minimizeTurns = ({
|
|
|
242
209
|
const finalSimplifiedPath = simplifyPath(optimizedPath)
|
|
243
210
|
return finalSimplifiedPath
|
|
244
211
|
}
|
|
245
|
-
|
|
246
|
-
export const minimizeTurnsWithFilteredLabels = ({
|
|
247
|
-
traces,
|
|
248
|
-
problem,
|
|
249
|
-
allLabelPlacements,
|
|
250
|
-
mergedLabelNetIdMap,
|
|
251
|
-
paddingBuffer,
|
|
252
|
-
}: {
|
|
253
|
-
traces: SolvedTracePath[]
|
|
254
|
-
problem: InputProblem
|
|
255
|
-
allLabelPlacements: NetLabelPlacement[]
|
|
256
|
-
mergedLabelNetIdMap: Map<string, Set<string>>
|
|
257
|
-
paddingBuffer: number
|
|
258
|
-
}): SolvedTracePath[] | null => {
|
|
259
|
-
let changesMade = false
|
|
260
|
-
const obstacles = getObstacleRects(problem)
|
|
261
|
-
|
|
262
|
-
const newTraces = traces.map((trace) => {
|
|
263
|
-
const originalPath = trace.tracePath
|
|
264
|
-
const filteredLabels = allLabelPlacements.filter((label) => {
|
|
265
|
-
const originalNetIds = mergedLabelNetIdMap.get(label.globalConnNetId)
|
|
266
|
-
if (originalNetIds) {
|
|
267
|
-
return !originalNetIds.has(trace.globalConnNetId)
|
|
268
|
-
}
|
|
269
|
-
return label.globalConnNetId !== trace.globalConnNetId
|
|
270
|
-
})
|
|
271
|
-
|
|
272
|
-
const labelBounds = filteredLabels.map((nl) => ({
|
|
273
|
-
minX: nl.center.x - nl.width / 2 - paddingBuffer,
|
|
274
|
-
maxX: nl.center.x + nl.width / 2 + paddingBuffer,
|
|
275
|
-
minY: nl.center.y - nl.height / 2 - paddingBuffer,
|
|
276
|
-
maxY: nl.center.y + nl.height / 2 + paddingBuffer,
|
|
277
|
-
}))
|
|
278
|
-
|
|
279
|
-
const newPath = minimizeTurns({
|
|
280
|
-
path: originalPath,
|
|
281
|
-
obstacles,
|
|
282
|
-
labelBounds,
|
|
283
|
-
})
|
|
284
|
-
|
|
285
|
-
if (
|
|
286
|
-
newPath.length !== originalPath.length ||
|
|
287
|
-
newPath.some(
|
|
288
|
-
(p, i) => p.x !== originalPath[i].x || p.y !== originalPath[i].y,
|
|
289
|
-
)
|
|
290
|
-
) {
|
|
291
|
-
changesMade = true
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
return {
|
|
295
|
-
...trace,
|
|
296
|
-
tracePath: newPath,
|
|
297
|
-
}
|
|
298
|
-
})
|
|
299
|
-
|
|
300
|
-
if (changesMade) {
|
|
301
|
-
return newTraces
|
|
302
|
-
} else {
|
|
303
|
-
return null
|
|
304
|
-
}
|
|
305
|
-
}
|
package/package.json
CHANGED
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
<svg width="640" height="640" viewBox="0 0 640 640" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<rect width="100%" height="100%" fill="white" />
|
|
3
|
+
<g>
|
|
4
|
+
<circle data-type="point" data-label="U1.1
|
|
5
|
+
y+" data-x="-0.2" data-y="1.4" cx="307.82608695652175" cy="228.69565217391306" r="3" fill="hsl(319, 100%, 50%, 0.8)" />
|
|
6
|
+
</g>
|
|
7
|
+
<g>
|
|
8
|
+
<circle data-type="point" data-label="U1.2
|
|
9
|
+
x-" data-x="-1.3" data-y="0.09999999999999998" cx="240.8695652173913" cy="307.82608695652175" r="3" fill="hsl(320, 100%, 50%, 0.8)" />
|
|
10
|
+
</g>
|
|
11
|
+
<g>
|
|
12
|
+
<circle data-type="point" data-label="U1.3
|
|
13
|
+
x-" data-x="-1.3" data-y="-0.10000000000000009" cx="240.8695652173913" cy="320" r="3" fill="hsl(321, 100%, 50%, 0.8)" />
|
|
14
|
+
</g>
|
|
15
|
+
<g>
|
|
16
|
+
<circle data-type="point" data-label="U1.4
|
|
17
|
+
x-" data-x="-1.3" data-y="-0.30000000000000004" cx="240.8695652173913" cy="332.17391304347825" r="3" fill="hsl(322, 100%, 50%, 0.8)" />
|
|
18
|
+
</g>
|
|
19
|
+
<g>
|
|
20
|
+
<circle data-type="point" data-label="U1.5
|
|
21
|
+
x-" data-x="-1.3" data-y="-0.5" cx="240.8695652173913" cy="344.3478260869565" r="3" fill="hsl(323, 100%, 50%, 0.8)" />
|
|
22
|
+
</g>
|
|
23
|
+
<g>
|
|
24
|
+
<circle data-type="point" data-label="U1.7
|
|
25
|
+
y-" data-x="0" data-y="-1.4" cx="320" cy="399.1304347826087" r="3" fill="hsl(325, 100%, 50%, 0.8)" />
|
|
26
|
+
</g>
|
|
27
|
+
<g>
|
|
28
|
+
<circle data-type="point" data-label="U1.8
|
|
29
|
+
x-" data-x="-1.3" data-y="0.5" cx="240.8695652173913" cy="283.47826086956525" r="3" fill="hsl(326, 100%, 50%, 0.8)" />
|
|
30
|
+
</g>
|
|
31
|
+
<g>
|
|
32
|
+
<circle data-type="point" data-label="U1.10
|
|
33
|
+
x+" data-x="1.3" data-y="-0.5" cx="399.1304347826087" cy="344.3478260869565" r="3" fill="hsl(217, 100%, 50%, 0.8)" />
|
|
34
|
+
</g>
|
|
35
|
+
<g>
|
|
36
|
+
<circle data-type="point" data-label="U1.11
|
|
37
|
+
x+" data-x="1.3" data-y="-0.3" cx="399.1304347826087" cy="332.17391304347825" r="3" fill="hsl(218, 100%, 50%, 0.8)" />
|
|
38
|
+
</g>
|
|
39
|
+
<g>
|
|
40
|
+
<circle data-type="point" data-label="U1.12
|
|
41
|
+
x+" data-x="1.3" data-y="-0.09999999999999998" cx="399.1304347826087" cy="320" r="3" fill="hsl(219, 100%, 50%, 0.8)" />
|
|
42
|
+
</g>
|
|
43
|
+
<g>
|
|
44
|
+
<circle data-type="point" data-label="U1.13
|
|
45
|
+
x+" data-x="1.3" data-y="0.10000000000000009" cx="399.1304347826087" cy="307.82608695652175" r="3" fill="hsl(220, 100%, 50%, 0.8)" />
|
|
46
|
+
</g>
|
|
47
|
+
<g>
|
|
48
|
+
<circle data-type="point" data-label="U1.14
|
|
49
|
+
y+" data-x="0.2" data-y="1.4" cx="332.17391304347825" cy="228.69565217391306" r="3" fill="hsl(221, 100%, 50%, 0.8)" />
|
|
50
|
+
</g>
|
|
51
|
+
<g>
|
|
52
|
+
<circle data-type="point" data-label="JP1.1
|
|
53
|
+
x+" data-x="-3.4" data-y="-0.8999999999999999" cx="113.04347826086953" cy="368.69565217391306" r="3" fill="hsl(358, 100%, 50%, 0.8)" />
|
|
54
|
+
</g>
|
|
55
|
+
<g>
|
|
56
|
+
<circle data-type="point" data-label="JP1.2
|
|
57
|
+
x+" data-x="-3.4" data-y="-0.7" cx="113.04347826086953" cy="356.5217391304348" r="3" fill="hsl(359, 100%, 50%, 0.8)" />
|
|
58
|
+
</g>
|
|
59
|
+
<g>
|
|
60
|
+
<circle data-type="point" data-label="JP1.3
|
|
61
|
+
x+" data-x="-3.4" data-y="-0.49999999999999994" cx="113.04347826086953" cy="344.3478260869565" r="3" fill="hsl(0, 100%, 50%, 0.8)" />
|
|
62
|
+
</g>
|
|
63
|
+
<g>
|
|
64
|
+
<circle data-type="point" data-label="JP1.4
|
|
65
|
+
x+" data-x="-3.4" data-y="-0.2999999999999999" cx="113.04347826086953" cy="332.17391304347825" r="3" fill="hsl(1, 100%, 50%, 0.8)" />
|
|
66
|
+
</g>
|
|
67
|
+
<g>
|
|
68
|
+
<circle data-type="point" data-label="JP1.5
|
|
69
|
+
x+" data-x="-3.4" data-y="-0.09999999999999992" cx="113.04347826086953" cy="320" r="3" fill="hsl(2, 100%, 50%, 0.8)" />
|
|
70
|
+
</g>
|
|
71
|
+
<g>
|
|
72
|
+
<circle data-type="point" data-label="JP1.6
|
|
73
|
+
x+" data-x="-3.4" data-y="0.10000000000000003" cx="113.04347826086953" cy="307.82608695652175" r="3" fill="hsl(3, 100%, 50%, 0.8)" />
|
|
74
|
+
</g>
|
|
75
|
+
<g>
|
|
76
|
+
<circle data-type="point" data-label="JP1.7
|
|
77
|
+
x+" data-x="-3.4" data-y="0.3" cx="113.04347826086953" cy="295.6521739130435" r="3" fill="hsl(4, 100%, 50%, 0.8)" />
|
|
78
|
+
</g>
|
|
79
|
+
<g>
|
|
80
|
+
<circle data-type="point" data-label="JP2.1
|
|
81
|
+
x-" data-x="3.4" data-y="-0.8999999999999999" cx="526.9565217391305" cy="368.69565217391306" r="3" fill="hsl(239, 100%, 50%, 0.8)" />
|
|
82
|
+
</g>
|
|
83
|
+
<g>
|
|
84
|
+
<circle data-type="point" data-label="JP2.2
|
|
85
|
+
x-" data-x="3.4" data-y="-0.7" cx="526.9565217391305" cy="356.5217391304348" r="3" fill="hsl(240, 100%, 50%, 0.8)" />
|
|
86
|
+
</g>
|
|
87
|
+
<g>
|
|
88
|
+
<circle data-type="point" data-label="JP2.3
|
|
89
|
+
x-" data-x="3.4" data-y="-0.5" cx="526.9565217391305" cy="344.3478260869565" r="3" fill="hsl(241, 100%, 50%, 0.8)" />
|
|
90
|
+
</g>
|
|
91
|
+
<g>
|
|
92
|
+
<circle data-type="point" data-label="JP2.4
|
|
93
|
+
x-" data-x="3.4" data-y="-0.3000000000000001" cx="526.9565217391305" cy="332.17391304347825" r="3" fill="hsl(242, 100%, 50%, 0.8)" />
|
|
94
|
+
</g>
|
|
95
|
+
<g>
|
|
96
|
+
<circle data-type="point" data-label="JP2.5
|
|
97
|
+
x-" data-x="3.4" data-y="-0.10000000000000003" cx="526.9565217391305" cy="320" r="3" fill="hsl(243, 100%, 50%, 0.8)" />
|
|
98
|
+
</g>
|
|
99
|
+
<g>
|
|
100
|
+
<circle data-type="point" data-label="JP2.6
|
|
101
|
+
x-" data-x="3.4" data-y="0.09999999999999998" cx="526.9565217391305" cy="307.82608695652175" r="3" fill="hsl(244, 100%, 50%, 0.8)" />
|
|
102
|
+
</g>
|
|
103
|
+
<g>
|
|
104
|
+
<circle data-type="point" data-label="JP2.7
|
|
105
|
+
x-" data-x="3.4" data-y="0.3" cx="526.9565217391305" cy="295.6521739130435" r="3" fill="hsl(245, 100%, 50%, 0.8)" />
|
|
106
|
+
</g>
|
|
107
|
+
<g>
|
|
108
|
+
<circle data-type="point" data-label="" data-x="-3.4" data-y="-0.09999999999999992" cx="113.04347826086953" cy="320" r="3" fill="red" />
|
|
109
|
+
</g>
|
|
110
|
+
<g>
|
|
111
|
+
<circle data-type="point" data-label="" data-x="-3.4" data-y="-0.09999999999999992" cx="113.04347826086953" cy="320" r="3" fill="red" />
|
|
112
|
+
</g>
|
|
113
|
+
<g>
|
|
114
|
+
<circle data-type="point" data-label="" data-x="-2.35" data-y="-0.1" cx="176.9565217391304" cy="320" r="3" fill="orange" />
|
|
115
|
+
</g>
|
|
116
|
+
<g>
|
|
117
|
+
<circle data-type="point" data-label="" data-x="-2.35" data-y="-0.1" cx="176.9565217391304" cy="320" r="3" fill="orange" />
|
|
118
|
+
</g>
|
|
119
|
+
<g>
|
|
120
|
+
<circle data-type="point" data-label="" data-x="-1.3" data-y="-0.10000000000000009" cx="240.8695652173913" cy="320" r="3" fill="red" />
|
|
121
|
+
</g>
|
|
122
|
+
<g>
|
|
123
|
+
<circle data-type="point" data-label="" data-x="-1.3" data-y="-0.10000000000000009" cx="240.8695652173913" cy="320" r="3" fill="red" />
|
|
124
|
+
</g>
|
|
125
|
+
<g>
|
|
126
|
+
<polyline data-points="-3.4,-0.8999999999999999 0,-1.4" data-type="line" data-label="" points="113.04347826086953,368.69565217391306 320,399.1304347826087" fill="none" stroke="hsl(336, 100%, 50%, 0.8)" stroke-width="1" />
|
|
127
|
+
</g>
|
|
128
|
+
<g>
|
|
129
|
+
<polyline data-points="-3.4,-0.49999999999999994 -1.3,-0.5" data-type="line" data-label="" points="113.04347826086953,344.3478260869565 240.8695652173913,344.3478260869565" fill="none" stroke="hsl(336, 100%, 50%, 0.8)" stroke-width="1" />
|
|
130
|
+
</g>
|
|
131
|
+
<g>
|
|
132
|
+
<polyline data-points="-3.4,-0.2999999999999999 -1.3,-0.30000000000000004" data-type="line" data-label="" points="113.04347826086953,332.17391304347825 240.8695652173913,332.17391304347825" fill="none" stroke="hsl(336, 100%, 50%, 0.8)" stroke-width="1" />
|
|
133
|
+
</g>
|
|
134
|
+
<g>
|
|
135
|
+
<polyline data-points="-3.4,-0.09999999999999992 -1.3,-0.10000000000000009" data-type="line" data-label="" points="113.04347826086953,320 240.8695652173913,320" fill="none" stroke="hsl(336, 100%, 50%, 0.8)" stroke-width="1" />
|
|
136
|
+
</g>
|
|
137
|
+
<g>
|
|
138
|
+
<polyline data-points="-3.4,0.10000000000000003 -1.3,0.09999999999999998" data-type="line" data-label="" points="113.04347826086953,307.82608695652175 240.8695652173913,307.82608695652175" fill="none" stroke="hsl(336, 100%, 50%, 0.8)" stroke-width="1" />
|
|
139
|
+
</g>
|
|
140
|
+
<g>
|
|
141
|
+
<polyline data-points="3.4,-0.5 1.3,-0.5" data-type="line" data-label="" points="526.9565217391305,344.3478260869565 399.1304347826087,344.3478260869565" fill="none" stroke="hsl(24, 100%, 50%, 0.8)" stroke-width="1" />
|
|
142
|
+
</g>
|
|
143
|
+
<g>
|
|
144
|
+
<polyline data-points="3.4,-0.3000000000000001 1.3,-0.3" data-type="line" data-label="" points="526.9565217391305,332.17391304347825 399.1304347826087,332.17391304347825" fill="none" stroke="hsl(24, 100%, 50%, 0.8)" stroke-width="1" />
|
|
145
|
+
</g>
|
|
146
|
+
<g>
|
|
147
|
+
<polyline data-points="3.4,-0.10000000000000003 1.3,-0.09999999999999998" data-type="line" data-label="" points="526.9565217391305,320 399.1304347826087,320" fill="none" stroke="hsl(24, 100%, 50%, 0.8)" stroke-width="1" />
|
|
148
|
+
</g>
|
|
149
|
+
<g>
|
|
150
|
+
<polyline data-points="3.4,0.09999999999999998 1.3,0.10000000000000009" data-type="line" data-label="" points="526.9565217391305,307.82608695652175 399.1304347826087,307.82608695652175" fill="none" stroke="hsl(24, 100%, 50%, 0.8)" stroke-width="1" />
|
|
151
|
+
</g>
|
|
152
|
+
<g>
|
|
153
|
+
<polyline data-points="-0.2,1.4 -3.4,-0.7" data-type="line" data-label="" points="307.82608695652175,228.69565217391306 113.04347826086953,356.5217391304348" fill="none" stroke="hsl(73, 100%, 50%, 0.8)" stroke-width="1" stroke-dasharray="4 2" />
|
|
154
|
+
</g>
|
|
155
|
+
<g>
|
|
156
|
+
<polyline data-points="0,-1.4 -3.4,-0.8999999999999999" data-type="line" data-label="" points="320,399.1304347826087 113.04347826086953,368.69565217391306" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1" stroke-dasharray="4 2" />
|
|
157
|
+
</g>
|
|
158
|
+
<g>
|
|
159
|
+
<polyline data-points="0,-1.4 3.4,-0.8999999999999999" data-type="line" data-label="" points="320,399.1304347826087 526.9565217391305,368.69565217391306" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1" stroke-dasharray="4 2" />
|
|
160
|
+
</g>
|
|
161
|
+
<g>
|
|
162
|
+
<polyline data-points="-3.4,-0.8999999999999999 3.4,-0.8999999999999999" data-type="line" data-label="" points="113.04347826086953,368.69565217391306 526.9565217391305,368.69565217391306" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1" stroke-dasharray="4 2" />
|
|
163
|
+
</g>
|
|
164
|
+
<g>
|
|
165
|
+
<polyline data-points="0.2,1.4 3.4,-0.7" data-type="line" data-label="" points="332.17391304347825,228.69565217391306 526.9565217391305,356.5217391304348" fill="none" stroke="hsl(199, 100%, 50%, 0.8)" stroke-width="1" stroke-dasharray="4 2" />
|
|
166
|
+
</g>
|
|
167
|
+
<g>
|
|
168
|
+
<polyline data-points="0,-1.4 0,-1.5999999999999999 -1.7,-1.5999999999999999 -1.7,-0.8999999999999999 -3.4,-0.8999999999999999" data-type="line" data-label="" points="320,399.1304347826087 320,411.304347826087 216.52173913043475,411.304347826087 216.52173913043475,368.69565217391306 113.04347826086953,368.69565217391306" fill="none" stroke="black" stroke-width="1" />
|
|
169
|
+
</g>
|
|
170
|
+
<g>
|
|
171
|
+
<polyline data-points="3.4,-0.8999999999999999 1.6999999999999997,-0.8999999999999999 1.6999999999999997,-1.5999999999999999 0,-1.5999999999999999 0,-1.4" data-type="line" data-label="" points="526.9565217391305,368.69565217391306 423.47826086956525,368.69565217391306 423.47826086956525,411.304347826087 320,411.304347826087 320,399.1304347826087" fill="none" stroke="black" stroke-width="1" />
|
|
172
|
+
</g>
|
|
173
|
+
<g>
|
|
174
|
+
<polyline data-points="-3.4,-0.49999999999999994 -1.3,-0.5" data-type="line" data-label="" points="113.04347826086953,344.3478260869565 240.8695652173913,344.3478260869565" fill="none" stroke="black" stroke-width="1" />
|
|
175
|
+
</g>
|
|
176
|
+
<g>
|
|
177
|
+
<polyline data-points="-3.4,-0.2999999999999999 -1.3,-0.30000000000000004" data-type="line" data-label="" points="113.04347826086953,332.17391304347825 240.8695652173913,332.17391304347825" fill="none" stroke="black" stroke-width="1" />
|
|
178
|
+
</g>
|
|
179
|
+
<g>
|
|
180
|
+
<polyline data-points="-3.4,-0.09999999999999992 -1.3,-0.10000000000000009" data-type="line" data-label="" points="113.04347826086953,320 240.8695652173913,320" fill="none" stroke="black" stroke-width="1" />
|
|
181
|
+
</g>
|
|
182
|
+
<g>
|
|
183
|
+
<polyline data-points="-3.4,0.10000000000000003 -1.3,0.09999999999999998" data-type="line" data-label="" points="113.04347826086953,307.82608695652175 240.8695652173913,307.82608695652175" fill="none" stroke="black" stroke-width="1" />
|
|
184
|
+
</g>
|
|
185
|
+
<g>
|
|
186
|
+
<polyline data-points="3.4,-0.5 1.3,-0.5" data-type="line" data-label="" points="526.9565217391305,344.3478260869565 399.1304347826087,344.3478260869565" fill="none" stroke="black" stroke-width="1" />
|
|
187
|
+
</g>
|
|
188
|
+
<g>
|
|
189
|
+
<polyline data-points="3.4,-0.3000000000000001 1.3,-0.3" data-type="line" data-label="" points="526.9565217391305,332.17391304347825 399.1304347826087,332.17391304347825" fill="none" stroke="black" stroke-width="1" />
|
|
190
|
+
</g>
|
|
191
|
+
<g>
|
|
192
|
+
<polyline data-points="3.4,-0.10000000000000003 1.3,-0.09999999999999998" data-type="line" data-label="" points="526.9565217391305,320 399.1304347826087,320" fill="none" stroke="black" stroke-width="1" />
|
|
193
|
+
</g>
|
|
194
|
+
<g>
|
|
195
|
+
<polyline data-points="3.4,0.09999999999999998 1.3,0.10000000000000009" data-type="line" data-label="" points="526.9565217391305,307.82608695652175 399.1304347826087,307.82608695652175" fill="none" stroke="black" stroke-width="1" />
|
|
196
|
+
</g>
|
|
197
|
+
<g>
|
|
198
|
+
<rect data-type="rect" data-label="schematic_component_0" data-x="0" data-y="0" x="240.8695652173913" y="228.69565217391306" width="158.26086956521738" height="170.43478260869563" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.016428571428571428" />
|
|
199
|
+
</g>
|
|
200
|
+
<g>
|
|
201
|
+
<rect data-type="rect" data-label="schematic_component_1" data-x="-4" data-y="-0.3" x="40" y="283.47826086956525" width="73.04347826086953" height="97.39130434782606" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.016428571428571428" />
|
|
202
|
+
</g>
|
|
203
|
+
<g>
|
|
204
|
+
<rect data-type="rect" data-label="schematic_component_2" data-x="4" data-y="-0.3" x="526.9565217391305" y="283.47826086956525" width="73.0434782608695" height="97.39130434782606" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.016428571428571428" />
|
|
205
|
+
</g>
|
|
206
|
+
<g>
|
|
207
|
+
<rect data-type="rect" data-label="" data-x="-3.4" data-y="0.12510000000000007" x="106.95652173913041" y="292.6026086956522" width="12.17391304347828" height="27.391304347826065" fill="rgba(220, 0, 0, 0.25)" stroke="black" stroke-width="0.016428571428571428" />
|
|
208
|
+
</g>
|
|
209
|
+
<g>
|
|
210
|
+
<rect data-type="rect" data-label="" data-x="-3.4" data-y="-0.32509999999999994" x="106.95652173913041" y="320.00608695652176" width="12.17391304347828" height="27.391304347826065" fill="rgba(220, 0, 0, 0.25)" stroke="black" stroke-width="0.016428571428571428" />
|
|
211
|
+
</g>
|
|
212
|
+
<g>
|
|
213
|
+
<rect data-type="rect" data-label="" data-x="-2.35" data-y="0.1251" x="170.86956521739128" y="292.6026086956522" width="12.17391304347828" height="27.391304347826065" fill="rgba(220, 140, 0, 0.25)" stroke="black" stroke-width="0.016428571428571428" />
|
|
214
|
+
</g>
|
|
215
|
+
<g>
|
|
216
|
+
<rect data-type="rect" data-label="" data-x="-2.35" data-y="-0.3251" x="170.86956521739128" y="320.00608695652176" width="12.17391304347828" height="27.391304347826065" fill="rgba(220, 140, 0, 0.25)" stroke="black" stroke-width="0.016428571428571428" />
|
|
217
|
+
</g>
|
|
218
|
+
<g>
|
|
219
|
+
<rect data-type="rect" data-label="" data-x="-1.3" data-y="0.1250999999999999" x="234.78260869565216" y="292.6026086956522" width="12.17391304347828" height="27.39130434782612" fill="rgba(220, 0, 0, 0.25)" stroke="black" stroke-width="0.016428571428571428" />
|
|
220
|
+
</g>
|
|
221
|
+
<g>
|
|
222
|
+
<rect data-type="rect" data-label="" data-x="-1.3" data-y="-0.32510000000000006" x="234.78260869565216" y="320.00608695652176" width="12.17391304347828" height="27.391304347826065" fill="rgba(220, 0, 0, 0.25)" stroke="black" stroke-width="0.016428571428571428" />
|
|
223
|
+
</g>
|
|
224
|
+
<g id="crosshair" style="display: none">
|
|
225
|
+
<line id="crosshair-h" y1="0" y2="640" stroke="#666" stroke-width="0.5" />
|
|
226
|
+
<line id="crosshair-v" x1="0" x2="640" stroke="#666" stroke-width="0.5" /><text id="coordinates" font-family="monospace" font-size="12" fill="#666"></text>
|
|
227
|
+
</g>
|
|
228
|
+
<script>
|
|
229
|
+
<![CDATA[
|
|
230
|
+
document.currentScript.parentElement.addEventListener('mousemove', (e) => {
|
|
231
|
+
const svg = e.currentTarget;
|
|
232
|
+
const rect = svg.getBoundingClientRect();
|
|
233
|
+
const x = e.clientX - rect.left;
|
|
234
|
+
const y = e.clientY - rect.top;
|
|
235
|
+
const crosshair = svg.getElementById('crosshair');
|
|
236
|
+
const h = svg.getElementById('crosshair-h');
|
|
237
|
+
const v = svg.getElementById('crosshair-v');
|
|
238
|
+
const coords = svg.getElementById('coordinates');
|
|
239
|
+
|
|
240
|
+
crosshair.style.display = 'block';
|
|
241
|
+
h.setAttribute('x1', '0');
|
|
242
|
+
h.setAttribute('x2', '640');
|
|
243
|
+
h.setAttribute('y1', y);
|
|
244
|
+
h.setAttribute('y2', y);
|
|
245
|
+
v.setAttribute('x1', x);
|
|
246
|
+
v.setAttribute('x2', x);
|
|
247
|
+
v.setAttribute('y1', '0');
|
|
248
|
+
v.setAttribute('y2', '640');
|
|
249
|
+
|
|
250
|
+
// Calculate real coordinates using inverse transformation
|
|
251
|
+
const matrix = {
|
|
252
|
+
"a": 60.86956521739131,
|
|
253
|
+
"c": 0,
|
|
254
|
+
"e": 320,
|
|
255
|
+
"b": 0,
|
|
256
|
+
"d": -60.86956521739131,
|
|
257
|
+
"f": 313.9130434782609
|
|
258
|
+
};
|
|
259
|
+
// Manually invert and apply the affine transform
|
|
260
|
+
// Since we only use translate and scale, we can directly compute:
|
|
261
|
+
// x' = (x - tx) / sx
|
|
262
|
+
// y' = (y - ty) / sy
|
|
263
|
+
const sx = matrix.a;
|
|
264
|
+
const sy = matrix.d;
|
|
265
|
+
const tx = matrix.e;
|
|
266
|
+
const ty = matrix.f;
|
|
267
|
+
const realPoint = {
|
|
268
|
+
x: (x - tx) / sx,
|
|
269
|
+
y: (y - ty) / sy // Flip y back since we used negative scale
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
coords.textContent = `(${realPoint.x.toFixed(2)}, ${realPoint.y.toFixed(2)})`;
|
|
273
|
+
coords.setAttribute('x', (x + 5).toString());
|
|
274
|
+
coords.setAttribute('y', (y - 5).toString());
|
|
275
|
+
});
|
|
276
|
+
document.currentScript.parentElement.addEventListener('mouseleave', () => {
|
|
277
|
+
document.currentScript.parentElement.getElementById('crosshair').style.display = 'none';
|
|
278
|
+
});
|
|
279
|
+
]]>
|
|
280
|
+
</script>
|
|
281
|
+
</svg>
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import { test, expect } from "bun:test"
|
|
2
|
+
import type { InputProblem } from "lib/index"
|
|
3
|
+
import { SchematicTracePipelineSolver } from "lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver"
|
|
4
|
+
import "tests/fixtures/matcher"
|
|
5
|
+
|
|
6
|
+
const inputProblem: InputProblem = {
|
|
7
|
+
chips: [
|
|
8
|
+
{
|
|
9
|
+
chipId: "schematic_component_0",
|
|
10
|
+
center: {
|
|
11
|
+
x: 0,
|
|
12
|
+
y: 0,
|
|
13
|
+
},
|
|
14
|
+
width: 1.8,
|
|
15
|
+
height: 2,
|
|
16
|
+
pins: [
|
|
17
|
+
{
|
|
18
|
+
pinId: "U1.1",
|
|
19
|
+
x: -0.2,
|
|
20
|
+
y: 1.4,
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
pinId: "U1.2",
|
|
24
|
+
x: -1.3,
|
|
25
|
+
y: 0.09999999999999998,
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
pinId: "U1.3",
|
|
29
|
+
x: -1.3,
|
|
30
|
+
y: -0.10000000000000009,
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
pinId: "U1.4",
|
|
34
|
+
x: -1.3,
|
|
35
|
+
y: -0.30000000000000004,
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
pinId: "U1.5",
|
|
39
|
+
x: -1.3,
|
|
40
|
+
y: -0.5,
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
pinId: "U1.7",
|
|
44
|
+
x: 0,
|
|
45
|
+
y: -1.4,
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
pinId: "U1.8",
|
|
49
|
+
x: -1.3,
|
|
50
|
+
y: 0.5,
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
pinId: "U1.10",
|
|
54
|
+
x: 1.3,
|
|
55
|
+
y: -0.5,
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
pinId: "U1.11",
|
|
59
|
+
x: 1.3,
|
|
60
|
+
y: -0.3,
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
pinId: "U1.12",
|
|
64
|
+
x: 1.3,
|
|
65
|
+
y: -0.09999999999999998,
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
pinId: "U1.13",
|
|
69
|
+
x: 1.3,
|
|
70
|
+
y: 0.10000000000000009,
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
pinId: "U1.14",
|
|
74
|
+
x: 0.2,
|
|
75
|
+
y: 1.4,
|
|
76
|
+
},
|
|
77
|
+
],
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
chipId: "schematic_component_1",
|
|
81
|
+
center: {
|
|
82
|
+
x: -4,
|
|
83
|
+
y: -0.3,
|
|
84
|
+
},
|
|
85
|
+
width: 0.4,
|
|
86
|
+
height: 1.6,
|
|
87
|
+
pins: [
|
|
88
|
+
{
|
|
89
|
+
pinId: "JP1.1",
|
|
90
|
+
x: -3.4,
|
|
91
|
+
y: -0.8999999999999999,
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
pinId: "JP1.2",
|
|
95
|
+
x: -3.4,
|
|
96
|
+
y: -0.7,
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
pinId: "JP1.3",
|
|
100
|
+
x: -3.4,
|
|
101
|
+
y: -0.49999999999999994,
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
pinId: "JP1.4",
|
|
105
|
+
x: -3.4,
|
|
106
|
+
y: -0.2999999999999999,
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
pinId: "JP1.5",
|
|
110
|
+
x: -3.4,
|
|
111
|
+
y: -0.09999999999999992,
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
pinId: "JP1.6",
|
|
115
|
+
x: -3.4,
|
|
116
|
+
y: 0.10000000000000003,
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
pinId: "JP1.7",
|
|
120
|
+
x: -3.4,
|
|
121
|
+
y: 0.3,
|
|
122
|
+
},
|
|
123
|
+
],
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
chipId: "schematic_component_2",
|
|
127
|
+
center: {
|
|
128
|
+
x: 4,
|
|
129
|
+
y: -0.3,
|
|
130
|
+
},
|
|
131
|
+
width: 0.4,
|
|
132
|
+
height: 1.6,
|
|
133
|
+
pins: [
|
|
134
|
+
{
|
|
135
|
+
pinId: "JP2.1",
|
|
136
|
+
x: 3.4,
|
|
137
|
+
y: -0.8999999999999999,
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
pinId: "JP2.2",
|
|
141
|
+
x: 3.4,
|
|
142
|
+
y: -0.7,
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
pinId: "JP2.3",
|
|
146
|
+
x: 3.4,
|
|
147
|
+
y: -0.5,
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
pinId: "JP2.4",
|
|
151
|
+
x: 3.4,
|
|
152
|
+
y: -0.3000000000000001,
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
pinId: "JP2.5",
|
|
156
|
+
x: 3.4,
|
|
157
|
+
y: -0.10000000000000003,
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
pinId: "JP2.6",
|
|
161
|
+
x: 3.4,
|
|
162
|
+
y: 0.09999999999999998,
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
pinId: "JP2.7",
|
|
166
|
+
x: 3.4,
|
|
167
|
+
y: 0.3,
|
|
168
|
+
},
|
|
169
|
+
],
|
|
170
|
+
},
|
|
171
|
+
],
|
|
172
|
+
directConnections: [
|
|
173
|
+
{
|
|
174
|
+
pinIds: ["JP1.1", "U1.7"],
|
|
175
|
+
netId: "pinheader.JP1 > port.pin1 to .U1 > .pin7",
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
pinIds: ["JP1.3", "U1.5"],
|
|
179
|
+
netId: "pinheader.JP1 > port.pin3 to .U1 > .pin5",
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
pinIds: ["JP1.4", "U1.4"],
|
|
183
|
+
netId: "pinheader.JP1 > port.pin4 to .U1 > .pin4",
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
pinIds: ["JP1.5", "U1.3"],
|
|
187
|
+
netId: "pinheader.JP1 > port.pin5 to .U1 > .pin3",
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
pinIds: ["JP1.6", "U1.2"],
|
|
191
|
+
netId: "pinheader.JP1 > port.pin6 to .U1 > .pin2",
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
pinIds: ["JP2.3", "U1.10"],
|
|
195
|
+
netId: "pinheader.JP2 > port.pin3 to .U1 > .pin10",
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
pinIds: ["JP2.4", "U1.11"],
|
|
199
|
+
netId: "pinheader.JP2 > port.pin4 to .U1 > .pin11",
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
pinIds: ["JP2.5", "U1.12"],
|
|
203
|
+
netId: "pinheader.JP2 > port.pin5 to .U1 > .pin12",
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
pinIds: ["JP2.6", "U1.13"],
|
|
207
|
+
netId: "pinheader.JP2 > port.pin6 to .U1 > .pin13",
|
|
208
|
+
},
|
|
209
|
+
],
|
|
210
|
+
netConnections: [
|
|
211
|
+
{
|
|
212
|
+
netId: "V3_3",
|
|
213
|
+
pinIds: ["U1.1", "JP1.2"],
|
|
214
|
+
netLabelWidth: 0.4,
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
netId: "GND",
|
|
218
|
+
pinIds: ["U1.7", "JP1.1", "JP2.1"],
|
|
219
|
+
netLabelWidth: 0.3,
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
netId: "V5",
|
|
223
|
+
pinIds: ["U1.14", "JP2.2"],
|
|
224
|
+
netLabelWidth: 0.2,
|
|
225
|
+
},
|
|
226
|
+
],
|
|
227
|
+
availableNetLabelOrientations: {
|
|
228
|
+
V3_3: ["y+"],
|
|
229
|
+
V5: ["y+"],
|
|
230
|
+
GND: ["y-"],
|
|
231
|
+
},
|
|
232
|
+
maxMspPairDistance: 5,
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
test("example01", () => {
|
|
236
|
+
const solver = new SchematicTracePipelineSolver(inputProblem)
|
|
237
|
+
|
|
238
|
+
solver.solve()
|
|
239
|
+
|
|
240
|
+
expect(solver).toMatchSolverSnapshot(import.meta.path)
|
|
241
|
+
})
|