@tscircuit/schematic-trace-solver 0.0.99 → 0.0.101
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 +31 -8
- package/lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/SchematicTraceSingleLineSolver2.ts +26 -3
- package/lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/generateEndpointCollisionDetours.ts +5 -2
- package/lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/mid.ts +13 -3
- package/package.json +1 -1
- package/tests/examples/__snapshots__/example11.snap.svg +19 -23
- package/tests/repros/__snapshots__/repro47-endpoint-obstacle-detour.snap.svg +61 -0
- package/tests/repros/__snapshots__/repro5-escape-padded-text-obstacles.snap.svg +74 -0
- package/tests/repros/assets/repro47-endpoint-obstacle-detour.input.json +133 -0
- package/tests/repros/assets/repro5-escape-padded-text-obstacles.input.json +202 -0
- package/tests/repros/repro47-endpoint-obstacle-detour.test.ts +19 -0
- package/tests/repros/repro5-escape-padded-text-obstacles.test.ts +17 -0
- package/tests/solvers/SchematicTraceSingleLineSolver2/candidate-mids-from-set.test.ts +39 -0
- package/tests/solvers/SchematicTraceSingleLineSolver2/generate-endpoint-collision-detours.test.ts +37 -0
package/dist/index.js
CHANGED
|
@@ -801,6 +801,7 @@ var isPathCollidingWithObstacles = (path, obstacles) => {
|
|
|
801
801
|
|
|
802
802
|
// lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/mid.ts
|
|
803
803
|
var EPS2 = 1e-9;
|
|
804
|
+
var OBSTACLE_CLEARANCE = 0.2;
|
|
804
805
|
var aabbFromPoints = (a, b) => ({
|
|
805
806
|
minX: Math.min(a.x, b.x),
|
|
806
807
|
maxX: Math.max(a.x, b.x),
|
|
@@ -815,7 +816,7 @@ var midBetweenPointAndRect = (axis, p, r, eps = EPS2) => {
|
|
|
815
816
|
if (p.x > r.maxX + eps) {
|
|
816
817
|
return [(p.x + r.maxX) / 2];
|
|
817
818
|
}
|
|
818
|
-
return [r.minX -
|
|
819
|
+
return [r.minX - OBSTACLE_CLEARANCE, r.maxX + OBSTACLE_CLEARANCE];
|
|
819
820
|
} else {
|
|
820
821
|
if (p.y < r.minY - eps) {
|
|
821
822
|
return [(p.y + r.minY) / 2];
|
|
@@ -823,10 +824,11 @@ var midBetweenPointAndRect = (axis, p, r, eps = EPS2) => {
|
|
|
823
824
|
if (p.y > r.maxY + eps) {
|
|
824
825
|
return [(p.y + r.maxY) / 2];
|
|
825
826
|
}
|
|
826
|
-
return [r.minY -
|
|
827
|
+
return [r.minY - OBSTACLE_CLEARANCE, r.maxY + OBSTACLE_CLEARANCE];
|
|
827
828
|
}
|
|
828
829
|
};
|
|
829
|
-
var candidateMidsFromSet = (axis, colliding, collisionRects, aabb,
|
|
830
|
+
var candidateMidsFromSet = (axis, colliding, collisionRects, aabb, opts = {}) => {
|
|
831
|
+
const { allowOpenSideCandidates = false, eps = EPS2 } = opts;
|
|
830
832
|
const setRects = [...collisionRects];
|
|
831
833
|
if (axis === "x") {
|
|
832
834
|
const leftBoundaries = [aabb.minX, ...setRects.map((r) => r.maxX)].filter(
|
|
@@ -840,9 +842,13 @@ var candidateMidsFromSet = (axis, colliding, collisionRects, aabb, eps = EPS2) =
|
|
|
840
842
|
const out = [];
|
|
841
843
|
if (leftNeighbor !== void 0) {
|
|
842
844
|
out.push((leftNeighbor + colliding.minX) / 2);
|
|
845
|
+
} else if (allowOpenSideCandidates) {
|
|
846
|
+
out.push(colliding.minX - OBSTACLE_CLEARANCE);
|
|
843
847
|
}
|
|
844
848
|
if (rightNeighbor !== void 0) {
|
|
845
849
|
out.push((colliding.maxX + rightNeighbor) / 2);
|
|
850
|
+
} else if (allowOpenSideCandidates) {
|
|
851
|
+
out.push(colliding.maxX + OBSTACLE_CLEARANCE);
|
|
846
852
|
}
|
|
847
853
|
return out;
|
|
848
854
|
} else {
|
|
@@ -857,9 +863,13 @@ var candidateMidsFromSet = (axis, colliding, collisionRects, aabb, eps = EPS2) =
|
|
|
857
863
|
const out = [];
|
|
858
864
|
if (bottomNeighbor !== void 0) {
|
|
859
865
|
out.push((bottomNeighbor + colliding.minY) / 2);
|
|
866
|
+
} else if (allowOpenSideCandidates) {
|
|
867
|
+
out.push(colliding.minY - OBSTACLE_CLEARANCE);
|
|
860
868
|
}
|
|
861
869
|
if (topNeighbor !== void 0) {
|
|
862
870
|
out.push((colliding.maxY + topNeighbor) / 2);
|
|
871
|
+
} else if (allowOpenSideCandidates) {
|
|
872
|
+
out.push(colliding.maxY + OBSTACLE_CLEARANCE);
|
|
863
873
|
}
|
|
864
874
|
return out;
|
|
865
875
|
}
|
|
@@ -884,7 +894,7 @@ var generateEndpointCollisionDetours = ({
|
|
|
884
894
|
collidingSegmentIndex,
|
|
885
895
|
obstacle
|
|
886
896
|
}) => {
|
|
887
|
-
if (path.length
|
|
897
|
+
if (path.length < 3 || path.length > 4) return [];
|
|
888
898
|
const lastSegmentIndex = path.length - 2;
|
|
889
899
|
if (collidingSegmentIndex !== 0 && collidingSegmentIndex !== lastSegmentIndex) {
|
|
890
900
|
return [];
|
|
@@ -907,7 +917,7 @@ var generateEndpointCollisionDetours = ({
|
|
|
907
917
|
const detours = [];
|
|
908
918
|
for (const escapeCoordinate of [...new Set(escapeCoordinates)]) {
|
|
909
919
|
for (const detourCoordinate of [...new Set(detourCoordinates)]) {
|
|
910
|
-
const
|
|
920
|
+
const orderedDetourPrefix = firstSegmentAxis === "y" ? [
|
|
911
921
|
start,
|
|
912
922
|
{ x: escapeCoordinate, y: start.y },
|
|
913
923
|
{ x: escapeCoordinate, y: detourCoordinate },
|
|
@@ -920,6 +930,7 @@ var generateEndpointCollisionDetours = ({
|
|
|
920
930
|
{ x: detourCoordinate, y: end.y },
|
|
921
931
|
end
|
|
922
932
|
];
|
|
933
|
+
const orderedDetour = [...orderedDetourPrefix, ...orderedPath.slice(3)];
|
|
923
934
|
const detour = shouldReverse ? orderedDetour.reverse() : orderedDetour;
|
|
924
935
|
if (hasOnlyNonzeroOrthogonalSegments(detour)) detours.push(detour);
|
|
925
936
|
}
|
|
@@ -1277,7 +1288,9 @@ var SchematicTraceSingleLineSolver2 = class extends BaseSolver {
|
|
|
1277
1288
|
let { segIndex, rect } = collision;
|
|
1278
1289
|
const isFirstSegment = segIndex === 0;
|
|
1279
1290
|
const isLastSegment = segIndex === path.length - 2;
|
|
1280
|
-
|
|
1291
|
+
const isEndpointChipObstacle = rect.kind === "chip" && this.pins.some((pin) => pin.chipId === rect.chipId);
|
|
1292
|
+
const canGenerateEndpointDetour = path.length === 3 || path.length === 4 && this.connectionPair !== void 0 && !isEndpointChipObstacle;
|
|
1293
|
+
if (canGenerateEndpointDetour && (isFirstSegment || isLastSegment)) {
|
|
1281
1294
|
const detours = generateEndpointCollisionDetours({
|
|
1282
1295
|
path,
|
|
1283
1296
|
collidingSegmentIndex: segIndex,
|
|
@@ -1318,6 +1331,9 @@ var SchematicTraceSingleLineSolver2 = class extends BaseSolver {
|
|
|
1318
1331
|
return;
|
|
1319
1332
|
}
|
|
1320
1333
|
const candidates = [];
|
|
1334
|
+
const candidateMidOptions = {
|
|
1335
|
+
allowOpenSideCandidates: this.connectionPair !== void 0
|
|
1336
|
+
};
|
|
1321
1337
|
if (collisionRects.size === 0) {
|
|
1322
1338
|
const m1 = midBetweenPointAndRect(axis, { x: PA.x, y: PA.y }, rect);
|
|
1323
1339
|
const m2 = midBetweenPointAndRect(axis, { x: PB.x, y: PB.y }, rect);
|
|
@@ -1325,7 +1341,13 @@ var SchematicTraceSingleLineSolver2 = class extends BaseSolver {
|
|
|
1325
1341
|
const uniqueCandidates = [...new Set(allCandidates)];
|
|
1326
1342
|
candidates.push(...uniqueCandidates);
|
|
1327
1343
|
} else {
|
|
1328
|
-
const mids = candidateMidsFromSet(
|
|
1344
|
+
const mids = candidateMidsFromSet(
|
|
1345
|
+
axis,
|
|
1346
|
+
rect,
|
|
1347
|
+
collisionRects,
|
|
1348
|
+
this.aabb,
|
|
1349
|
+
candidateMidOptions
|
|
1350
|
+
);
|
|
1329
1351
|
candidates.push(...mids);
|
|
1330
1352
|
}
|
|
1331
1353
|
const newStates = [];
|
|
@@ -1371,7 +1393,8 @@ var SchematicTraceSingleLineSolver2 = class extends BaseSolver {
|
|
|
1371
1393
|
adjacentAxis,
|
|
1372
1394
|
rect,
|
|
1373
1395
|
collisionRects,
|
|
1374
|
-
this.aabb
|
|
1396
|
+
this.aabb,
|
|
1397
|
+
candidateMidOptions
|
|
1375
1398
|
)
|
|
1376
1399
|
);
|
|
1377
1400
|
}
|
|
@@ -357,8 +357,19 @@ export class SchematicTraceSingleLineSolver2 extends BaseSolver {
|
|
|
357
357
|
// Never move the first or last segments - move adjacent segment instead
|
|
358
358
|
const isFirstSegment = segIndex === 0
|
|
359
359
|
const isLastSegment = segIndex === path.length - 2
|
|
360
|
-
|
|
361
|
-
|
|
360
|
+
const isEndpointChipObstacle =
|
|
361
|
+
rect.kind === "chip" &&
|
|
362
|
+
this.pins.some((pin) => pin.chipId === rect.chipId)
|
|
363
|
+
// U-shaped detours are local repairs for fixed MSP pairs obstructed by an
|
|
364
|
+
// intermediate obstacle. Endpoint-chip and optional long-distance routing
|
|
365
|
+
// require multi-trace or net-level selection instead.
|
|
366
|
+
const canGenerateEndpointDetour =
|
|
367
|
+
path.length === 3 ||
|
|
368
|
+
(path.length === 4 &&
|
|
369
|
+
this.connectionPair !== undefined &&
|
|
370
|
+
!isEndpointChipObstacle)
|
|
371
|
+
|
|
372
|
+
if (canGenerateEndpointDetour && (isFirstSegment || isLastSegment)) {
|
|
362
373
|
const detours = generateEndpointCollisionDetours({
|
|
363
374
|
path,
|
|
364
375
|
collidingSegmentIndex: segIndex,
|
|
@@ -413,6 +424,11 @@ export class SchematicTraceSingleLineSolver2 extends BaseSolver {
|
|
|
413
424
|
|
|
414
425
|
// Note: PA and PB are already defined above
|
|
415
426
|
const candidates: number[] = []
|
|
427
|
+
// Fixed MSP pairs may leave the endpoint bounds to complete a required
|
|
428
|
+
// route. Optional long-distance candidates retain their bounded search.
|
|
429
|
+
const candidateMidOptions = {
|
|
430
|
+
allowOpenSideCandidates: this.connectionPair !== undefined,
|
|
431
|
+
}
|
|
416
432
|
|
|
417
433
|
if (collisionRects.size === 0) {
|
|
418
434
|
// First collision on this search branch: use mid(PA, C) and mid(PB, C)
|
|
@@ -425,7 +441,13 @@ export class SchematicTraceSingleLineSolver2 extends BaseSolver {
|
|
|
425
441
|
candidates.push(...uniqueCandidates)
|
|
426
442
|
} else {
|
|
427
443
|
// Subsequent collisions: mid between C and nearest rect/bounds from the set
|
|
428
|
-
const mids = candidateMidsFromSet(
|
|
444
|
+
const mids = candidateMidsFromSet(
|
|
445
|
+
axis,
|
|
446
|
+
rect,
|
|
447
|
+
collisionRects,
|
|
448
|
+
this.aabb,
|
|
449
|
+
candidateMidOptions,
|
|
450
|
+
)
|
|
429
451
|
candidates.push(...mids)
|
|
430
452
|
}
|
|
431
453
|
|
|
@@ -496,6 +518,7 @@ export class SchematicTraceSingleLineSolver2 extends BaseSolver {
|
|
|
496
518
|
rect,
|
|
497
519
|
collisionRects,
|
|
498
520
|
this.aabb,
|
|
521
|
+
candidateMidOptions,
|
|
499
522
|
),
|
|
500
523
|
)
|
|
501
524
|
}
|
|
@@ -28,7 +28,9 @@ export const generateEndpointCollisionDetours = ({
|
|
|
28
28
|
collidingSegmentIndex: number
|
|
29
29
|
obstacle: ObstacleRect
|
|
30
30
|
}): Point[][] => {
|
|
31
|
-
|
|
31
|
+
// Endpoint detours expand the initial L- and U-shaped elbow candidates.
|
|
32
|
+
// Longer paths have already been expanded and are handled by segment shifts.
|
|
33
|
+
if (path.length < 3 || path.length > 4) return []
|
|
32
34
|
|
|
33
35
|
const lastSegmentIndex = path.length - 2
|
|
34
36
|
if (
|
|
@@ -58,7 +60,7 @@ export const generateEndpointCollisionDetours = ({
|
|
|
58
60
|
const detours: Point[][] = []
|
|
59
61
|
for (const escapeCoordinate of [...new Set(escapeCoordinates)]) {
|
|
60
62
|
for (const detourCoordinate of [...new Set(detourCoordinates)]) {
|
|
61
|
-
const
|
|
63
|
+
const orderedDetourPrefix =
|
|
62
64
|
firstSegmentAxis === "y"
|
|
63
65
|
? [
|
|
64
66
|
start!,
|
|
@@ -75,6 +77,7 @@ export const generateEndpointCollisionDetours = ({
|
|
|
75
77
|
end!,
|
|
76
78
|
]
|
|
77
79
|
|
|
80
|
+
const orderedDetour = [...orderedDetourPrefix, ...orderedPath.slice(3)]
|
|
78
81
|
const detour = shouldReverse ? orderedDetour.reverse() : orderedDetour
|
|
79
82
|
if (hasOnlyNonzeroOrthogonalSegments(detour)) detours.push(detour)
|
|
80
83
|
}
|
|
@@ -2,6 +2,7 @@ import type { Point } from "@tscircuit/math-utils"
|
|
|
2
2
|
import type { ObstacleRect } from "./rect"
|
|
3
3
|
|
|
4
4
|
const EPS = 1e-9
|
|
5
|
+
const OBSTACLE_CLEARANCE = 0.2
|
|
5
6
|
|
|
6
7
|
export type Axis = "x" | "y"
|
|
7
8
|
|
|
@@ -26,7 +27,7 @@ export const midBetweenPointAndRect = (
|
|
|
26
27
|
return [(p.x + r.maxX) / 2]
|
|
27
28
|
}
|
|
28
29
|
// Point is within rect bounds on this axis - generate candidates on both sides
|
|
29
|
-
return [r.minX -
|
|
30
|
+
return [r.minX - OBSTACLE_CLEARANCE, r.maxX + OBSTACLE_CLEARANCE]
|
|
30
31
|
} else {
|
|
31
32
|
if (p.y < r.minY - eps) {
|
|
32
33
|
return [(p.y + r.minY) / 2]
|
|
@@ -35,7 +36,7 @@ export const midBetweenPointAndRect = (
|
|
|
35
36
|
return [(p.y + r.maxY) / 2]
|
|
36
37
|
}
|
|
37
38
|
// Point is within rect bounds on this axis - generate candidates on both sides
|
|
38
|
-
return [r.minY -
|
|
39
|
+
return [r.minY - OBSTACLE_CLEARANCE, r.maxY + OBSTACLE_CLEARANCE]
|
|
39
40
|
}
|
|
40
41
|
}
|
|
41
42
|
|
|
@@ -44,8 +45,9 @@ export const candidateMidsFromSet = (
|
|
|
44
45
|
colliding: ObstacleRect,
|
|
45
46
|
collisionRects: Set<ObstacleRect>,
|
|
46
47
|
aabb: { minX: number; maxX: number; minY: number; maxY: number },
|
|
47
|
-
eps =
|
|
48
|
+
opts: { allowOpenSideCandidates?: boolean; eps?: number } = {},
|
|
48
49
|
): number[] => {
|
|
50
|
+
const { allowOpenSideCandidates = false, eps = EPS } = opts
|
|
49
51
|
const setRects = [...collisionRects]
|
|
50
52
|
|
|
51
53
|
if (axis === "x") {
|
|
@@ -64,9 +66,13 @@ export const candidateMidsFromSet = (
|
|
|
64
66
|
const out: number[] = []
|
|
65
67
|
if (leftNeighbor !== undefined) {
|
|
66
68
|
out.push((leftNeighbor + colliding.minX) / 2)
|
|
69
|
+
} else if (allowOpenSideCandidates) {
|
|
70
|
+
out.push(colliding.minX - OBSTACLE_CLEARANCE)
|
|
67
71
|
}
|
|
68
72
|
if (rightNeighbor !== undefined) {
|
|
69
73
|
out.push((colliding.maxX + rightNeighbor) / 2)
|
|
74
|
+
} else if (allowOpenSideCandidates) {
|
|
75
|
+
out.push(colliding.maxX + OBSTACLE_CLEARANCE)
|
|
70
76
|
}
|
|
71
77
|
return out
|
|
72
78
|
} else {
|
|
@@ -85,9 +91,13 @@ export const candidateMidsFromSet = (
|
|
|
85
91
|
const out: number[] = []
|
|
86
92
|
if (bottomNeighbor !== undefined) {
|
|
87
93
|
out.push((bottomNeighbor + colliding.minY) / 2)
|
|
94
|
+
} else if (allowOpenSideCandidates) {
|
|
95
|
+
out.push(colliding.minY - OBSTACLE_CLEARANCE)
|
|
88
96
|
}
|
|
89
97
|
if (topNeighbor !== undefined) {
|
|
90
98
|
out.push((colliding.maxY + topNeighbor) / 2)
|
|
99
|
+
} else if (allowOpenSideCandidates) {
|
|
100
|
+
out.push(colliding.maxY + OBSTACLE_CLEARANCE)
|
|
91
101
|
}
|
|
92
102
|
return out
|
|
93
103
|
}
|
package/package.json
CHANGED
|
@@ -1,25 +1,21 @@
|
|
|
1
|
-
<svg width="640" height="640" viewBox="0 0 640 640" xmlns="http://www.w3.org/2000/svg"><rect width="100%" height="100%" fill="white"/><g><polyline data-points="0.48,0.765 -0.48,-0.765" data-type="line" data-label="" points="
|
|
2
|
-
globalConnNetId: connectivity_net2" data-x="0.
|
|
3
|
-
globalConnNetId:
|
|
4
|
-
globalConnNetId:
|
|
5
|
-
globalConnNetId:
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
x-" data-x="
|
|
9
|
-
x+" data-x="
|
|
10
|
-
x-" data-x="
|
|
11
|
-
x+" data-x="
|
|
12
|
-
x-" data-x="
|
|
13
|
-
|
|
14
|
-
x
|
|
15
|
-
y
|
|
16
|
-
|
|
17
|
-
orientation:
|
|
18
|
-
orientation:
|
|
19
|
-
orientation: x+" data-x="1.48" data-y="-0.665" cx="536.2544169611307" cy="427.0671378091873" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
|
|
20
|
-
orientation: x+" data-x="-0.48" data-y="0.765" cx="259.2226148409894" cy="224.94699646643113" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
|
|
21
|
-
orientation: y+" data-x="0.24" data-y="0.765" cx="360.9893992932862" cy="224.94699646643113" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
|
|
22
|
-
orientation: y+" data-x="1.7800000000000002" data-y="0.765" cx="578.6572438162544" cy="224.94699646643113" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g id="crosshair" style="display: none"><line id="crosshair-h" y1="0" y2="640" stroke="#666" stroke-width="0.5"/><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></g><script><![CDATA[
|
|
1
|
+
<svg width="640" height="640" viewBox="0 0 640 640" xmlns="http://www.w3.org/2000/svg"><rect width="100%" height="100%" fill="white"/><g><polyline data-points="0.48,0.765 -0.48,-0.765" data-type="line" data-label="" points="391.4893617021276,213.51063829787233 248.51063829787228,441.3829787234042" fill="none" stroke="hsl(224, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="1.58,0.765 -1.58,-0.765" data-type="line" data-label="" points="555.3191489361701,213.51063829787233 84.68085106382975,441.3829787234042" fill="none" stroke="hsl(224, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="0.5800000000000001,-0.665 -1.58,0.765" data-type="line" data-label="" points="406.3829787234042,426.48936170212767 84.68085106382975,213.51063829787233" fill="none" stroke="hsl(168, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="1.48,-0.665 -0.48,0.765" data-type="line" data-label="" points="540.4255319148936,426.48936170212767 248.51063829787228,213.51063829787233" fill="none" stroke="hsl(168, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="0.48,0.765 0.27999999999999997,0.765 0.27999999999999997,0.665 -0.1,0.665 -0.1,-0.765 -0.48,-0.765" data-type="line" data-label="" points="391.4893617021276,213.51063829787233 361.7021276595744,213.51063829787233 361.7021276595744,228.40425531914892 305.10638297872333,228.40425531914892 305.10638297872333,441.3829787234042 248.51063829787228,441.3829787234042" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="1.58,0.765 1.7800000000000002,0.765 1.7800000000000002,0 -1.8800000000000001,0 -1.8800000000000001,-0.765 -1.58,-0.765" data-type="line" data-label="" points="555.3191489361701,213.51063829787233 585.1063829787233,213.51063829787233 585.1063829787233,327.4468085106383 39.99999999999994,327.4468085106383 39.99999999999994,441.3829787234042 84.68085106382975,441.3829787234042" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="0.5800000000000001,-0.665 0.050000000000000044,-0.665 0.050000000000000044,-0.37054465000000053 -1.68,-0.37054465000000053 -1.68,0.765 -1.58,0.765" data-type="line" data-label="" points="406.3829787234042,426.48936170212767 327.4468085106382,426.48936170212767 327.4468085106382,382.63430957446815 69.78723404255317,382.63430957446815 69.78723404255317,213.51063829787233 84.68085106382975,213.51063829787233" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="1.48,-0.665 1.68,-0.665 1.68,0.37054465000000053 0.1,0.37054465000000053 0.1,0.865 -0.38,0.865 -0.38,0.765 -0.48,0.765" data-type="line" data-label="" points="540.4255319148936,426.48936170212767 570.2127659574467,426.48936170212767 570.2127659574467,272.2593074468084 334.89361702127655,272.2593074468084 334.89361702127655,198.61702127659575 263.4042553191489,198.61702127659575 263.4042553191489,213.51063829787233 248.51063829787228,213.51063829787233" fill="none" stroke="purple" stroke-width="1px"/></g><g><rect data-type="rect" data-label="schematic_component_0" data-x="-1.03" data-y="0.765" x="84.68085106382976" y="184.54920319148943" width="163.82978723404253" height="57.922870212765815" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.006714285714285715"/></g><g><rect data-type="rect" data-label="schematic_component_1" data-x="1.03" data-y="0.765" x="391.48936170212767" y="184.54920319148943" width="163.8297872340425" height="57.922870212765815" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.006714285714285715"/></g><g><rect data-type="rect" data-label="schematic_component_2" data-x="-1.03" data-y="-0.765" x="84.68085106382976" y="412.4215436170213" width="163.82978723404253" height="57.922870212765815" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.006714285714285715"/></g><g><rect data-type="rect" data-label="schematic_component_3" data-x="1.03" data-y="-0.765" x="406.3829787234042" y="401.9148936170212" width="134.04255319148933" height="78.936170212766" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.006714285714285715"/></g><g><rect data-type="rect" data-label="netId: .J1 > .pin1 to .R1 > .pin1
|
|
2
|
+
globalConnNetId: connectivity_net2" data-x="0.31500000000000006" data-y="-0.44000000000000006" x="352.0212765957446" y="359.468085106383" width="29.787234042553223" height="67.02127659574472" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.006714285714285715"/></g><g><rect data-type="rect" data-label="netId: .J1 > .pin3 to .R1 > .pin2
|
|
3
|
+
globalConnNetId: connectivity_net3" data-x="1.68" data-y="-0.89" x="555.31914893617" y="426.48936170212767" width="29.787234042553223" height="67.02127659574467" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.006714285714285715"/></g><g><rect data-type="rect" data-label="netId: .R2 > .pin1 to .R3 > .pin2
|
|
4
|
+
globalConnNetId: connectivity_net0" data-x="0.27999999999999997" data-y="0.99" x="346.8085106382978" y="146.48936170212767" width="29.787234042553166" height="67.0212765957447" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.006714285714285715"/></g><g><rect data-type="rect" data-label="netId: .R2 > .pin2 to .R3 > .pin1
|
|
5
|
+
globalConnNetId: connectivity_net1" data-x="1.7800000000000002" data-y="0.99" x="570.2127659574467" y="146.48936170212767" width="29.787234042553223" height="67.0212765957447" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.006714285714285715"/></g><g><circle data-type="point" data-label="R1.1
|
|
6
|
+
x-" data-x="-1.58" data-y="0.765" cx="84.68085106382975" cy="213.51063829787233" r="3" fill="hsl(226, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="R1.2
|
|
7
|
+
x+" data-x="-0.48" data-y="0.765" cx="248.51063829787228" cy="213.51063829787233" r="3" fill="hsl(227, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="R2.1
|
|
8
|
+
x-" data-x="0.48" data-y="0.765" cx="391.4893617021276" cy="213.51063829787233" r="3" fill="hsl(107, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="R2.2
|
|
9
|
+
x+" data-x="1.58" data-y="0.765" cx="555.3191489361701" cy="213.51063829787233" r="3" fill="hsl(108, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="R3.1
|
|
10
|
+
x-" data-x="-1.58" data-y="-0.765" cx="84.68085106382975" cy="441.3829787234042" r="3" fill="hsl(348, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="R3.2
|
|
11
|
+
x+" data-x="-0.48" data-y="-0.765" cx="248.51063829787228" cy="441.3829787234042" r="3" fill="hsl(349, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="J1.1
|
|
12
|
+
x-" data-x="0.5800000000000001" data-y="-0.665" cx="406.3829787234042" cy="426.48936170212767" r="3" fill="hsl(218, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="J1.2
|
|
13
|
+
y-" data-x="1.03" data-y="-1.03" cx="473.4042553191489" cy="480.8510638297872" r="3" fill="hsl(219, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="J1.3
|
|
14
|
+
x+" data-x="1.48" data-y="-0.665" cx="540.4255319148936" cy="426.48936170212767" r="3" fill="hsl(220, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="anchorPoint
|
|
15
|
+
orientation: y+" data-x="0.31500000000000006" data-y="-0.665" cx="366.9148936170212" cy="426.48936170212767" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
|
|
16
|
+
orientation: y-" data-x="1.68" data-y="-0.665" cx="570.2127659574467" cy="426.48936170212767" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
|
|
17
|
+
orientation: y+" data-x="0.27999999999999997" data-y="0.765" cx="361.7021276595744" cy="213.51063829787233" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
|
|
18
|
+
orientation: y+" data-x="1.7800000000000002" data-y="0.765" cx="585.1063829787233" cy="213.51063829787233" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g id="crosshair" style="display: none"><line id="crosshair-h" y1="0" y2="640" stroke="#666" stroke-width="0.5"/><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></g><script><![CDATA[
|
|
23
19
|
document.currentScript.parentElement.addEventListener('mousemove', (e) => {
|
|
24
20
|
const svg = e.currentTarget;
|
|
25
21
|
const rect = svg.getBoundingClientRect();
|
|
@@ -41,7 +37,7 @@ orientation: y+" data-x="1.7800000000000002" data-y="0.765" cx="578.657243816254
|
|
|
41
37
|
v.setAttribute('y2', '640');
|
|
42
38
|
|
|
43
39
|
// Calculate real coordinates using inverse transformation
|
|
44
|
-
const matrix = {"a":
|
|
40
|
+
const matrix = {"a":148.93617021276594,"c":0,"e":319.99999999999994,"b":0,"d":-148.93617021276594,"f":327.4468085106383};
|
|
45
41
|
// Manually invert and apply the affine transform
|
|
46
42
|
// Since we only use translate and scale, we can directly compute:
|
|
47
43
|
// x' = (x - tx) / sx
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
<svg width="640" height="640" viewBox="0 0 640 640" xmlns="http://www.w3.org/2000/svg"><rect width="100%" height="100%" fill="white"/><g><polyline data-points="0.6499999999999999,0.825 -0.6499999999999999,-0.825" data-type="line" data-label="" points="413.3333333333333,182.22222222222226 182.22222222222223,475.55555555555554" fill="none" stroke="hsl(224, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="1.25,0.825 -1.25,-0.825" data-type="line" data-label="" points="520,182.22222222222226 75.55555555555554,475.55555555555554" fill="none" stroke="hsl(224, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="0.49999999999999994,-0.725 -1.25,0.825" data-type="line" data-label="" points="386.66666666666663,457.7777777777778 75.55555555555554,182.22222222222226" fill="none" stroke="hsl(168, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="1.4,-0.725 -0.6499999999999999,0.825" data-type="line" data-label="" points="546.6666666666666,457.7777777777778 182.22222222222223,182.22222222222226" fill="none" stroke="hsl(168, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="0.6499999999999999,0.825 0.4499999999999999,0.825 0.4499999999999999,0.725 -0.1,0.725 -0.1,-0.825 -0.6499999999999999,-0.825" data-type="line" data-label="" points="413.3333333333333,182.22222222222226 377.77777777777777,182.22222222222226 377.77777777777777,200.00000000000003 280,200.00000000000003 280,475.55555555555554 182.22222222222223,475.55555555555554" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="1.25,0.825 1.4500000000000002,0.825 1.4500000000000002,0 -1.45,0 -1.45,-0.825 -1.25,-0.825" data-type="line" data-label="" points="520,182.22222222222226 555.5555555555557,182.22222222222226 555.5555555555557,328.8888888888889 40,328.8888888888889 40,475.55555555555554 75.55555555555554,475.55555555555554" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="0.5,-0.725 -0.07499999999999996,-0.725 -0.07499999999999996,0.17000000000000004 -1.45,0.17000000000000004 -1.45,0.825 -1.25,0.825" data-type="line" data-label="" points="386.66666666666663,457.7777777777778 284.44444444444446,457.7777777777778 284.44444444444446,298.6666666666667 40,298.6666666666667 40,182.22222222222226 75.55555555555554,182.22222222222226" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="1.4,-0.725 1.5999999999999999,-0.725 1.5999999999999999,0.28499999999999986 0.1,0.28499999999999986 0.1,0.825 -0.6499999999999999,0.825" data-type="line" data-label="" points="546.6666666666666,457.7777777777778 582.2222222222222,457.7777777777778 582.2222222222222,278.2222222222223 315.55555555555554,278.2222222222223 315.55555555555554,182.22222222222226 182.22222222222223,182.22222222222226" fill="none" stroke="purple" stroke-width="1px"/></g><g><rect data-type="rect" data-label="schematic_component_0" data-x="-0.95" data-y="0.825" x="75.55555555555554" y="121.7777777777778" width="106.66666666666669" height="120.88888888888891" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.005625"/></g><g><rect data-type="rect" data-label="schematic_component_1" data-x="0.95" data-y="0.825" x="413.33333333333326" y="121.7777777777778" width="106.66666666666669" height="120.88888888888891" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.005625"/></g><g><rect data-type="rect" data-label="schematic_component_2" data-x="-0.95" data-y="-0.825" x="75.55555555555554" y="415.1111111111111" width="106.66666666666669" height="120.88888888888891" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.005625"/></g><g><rect data-type="rect" data-label="schematic_component_3" data-x="0.95" data-y="-0.825" x="386.66666666666663" y="426.15489151111115" width="160" height="98.8013280888888" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.005625"/></g><g><rect data-type="rect" data-label="netId: .J1 > .pin1 to .R1 > .pin1
|
|
2
|
+
globalConnNetId: connectivity_net2" data-x="0.21250000000000002" data-y="-0.5" x="317.77777777777777" y="377.7777777777778" width="35.55555555555554" height="80" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.005625"/></g><g><rect data-type="rect" data-label="netId: .J1 > .pin3 to .R1 > .pin2
|
|
3
|
+
globalConnNetId: connectivity_net3" data-x="1.5999999999999999" data-y="-0.95" x="564.4444444444443" y="457.7777777777778" width="35.55555555555566" height="80" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.005625"/></g><g><rect data-type="rect" data-label="netId: .R2 > .pin1 to .R3 > .pin2
|
|
4
|
+
globalConnNetId: connectivity_net0" data-x="0.4499999999999999" data-y="1.05" x="360" y="102.22222222222226" width="35.5555555555556" height="80" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.005625"/></g><g><rect data-type="rect" data-label="netId: .R2 > .pin2 to .R3 > .pin1
|
|
5
|
+
globalConnNetId: connectivity_net1" data-x="1.4500000000000002" data-y="1.05" x="537.7777777777778" y="102.22222222222226" width="35.55555555555554" height="80" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.005625"/></g><g><circle data-type="point" data-label="R1.1
|
|
6
|
+
x-" data-x="-1.25" data-y="0.825" cx="75.55555555555554" cy="182.22222222222226" r="3" fill="hsl(226, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="R1.2
|
|
7
|
+
x+" data-x="-0.6499999999999999" data-y="0.825" cx="182.22222222222223" cy="182.22222222222226" r="3" fill="hsl(227, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="R2.1
|
|
8
|
+
x-" data-x="0.6499999999999999" data-y="0.825" cx="413.3333333333333" cy="182.22222222222226" r="3" fill="hsl(107, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="R2.2
|
|
9
|
+
x+" data-x="1.25" data-y="0.825" cx="520" cy="182.22222222222226" r="3" fill="hsl(108, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="R3.1
|
|
10
|
+
x-" data-x="-1.25" data-y="-0.825" cx="75.55555555555554" cy="475.55555555555554" r="3" fill="hsl(348, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="R3.2
|
|
11
|
+
x+" data-x="-0.6499999999999999" data-y="-0.825" cx="182.22222222222223" cy="475.55555555555554" r="3" fill="hsl(349, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="J1.1
|
|
12
|
+
x-" data-x="0.49999999999999994" data-y="-0.725" cx="386.66666666666663" cy="457.7777777777778" r="3" fill="hsl(218, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="J1.2
|
|
13
|
+
y-" data-x="0.95" data-y="-1.1028787352499998" cx="466.66666666666663" cy="524.9562195999999" r="3" fill="hsl(219, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="J1.3
|
|
14
|
+
x+" data-x="1.4" data-y="-0.725" cx="546.6666666666666" cy="457.7777777777778" r="3" fill="hsl(220, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="anchorPoint
|
|
15
|
+
orientation: y+" data-x="0.21250000000000002" data-y="-0.725" cx="335.55555555555554" cy="457.7777777777778" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
|
|
16
|
+
orientation: y-" data-x="1.5999999999999999" data-y="-0.725" cx="582.2222222222222" cy="457.7777777777778" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
|
|
17
|
+
orientation: y+" data-x="0.4499999999999999" data-y="0.825" cx="377.77777777777777" cy="182.22222222222226" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
|
|
18
|
+
orientation: y+" data-x="1.4500000000000002" data-y="0.825" cx="555.5555555555557" cy="182.22222222222226" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g id="crosshair" style="display: none"><line id="crosshair-h" y1="0" y2="640" stroke="#666" stroke-width="0.5"/><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></g><script><![CDATA[
|
|
19
|
+
document.currentScript.parentElement.addEventListener('mousemove', (e) => {
|
|
20
|
+
const svg = e.currentTarget;
|
|
21
|
+
const rect = svg.getBoundingClientRect();
|
|
22
|
+
const x = e.clientX - rect.left;
|
|
23
|
+
const y = e.clientY - rect.top;
|
|
24
|
+
const crosshair = svg.getElementById('crosshair');
|
|
25
|
+
const h = svg.getElementById('crosshair-h');
|
|
26
|
+
const v = svg.getElementById('crosshair-v');
|
|
27
|
+
const coords = svg.getElementById('coordinates');
|
|
28
|
+
|
|
29
|
+
crosshair.style.display = 'block';
|
|
30
|
+
h.setAttribute('x1', '0');
|
|
31
|
+
h.setAttribute('x2', '640');
|
|
32
|
+
h.setAttribute('y1', y);
|
|
33
|
+
h.setAttribute('y2', y);
|
|
34
|
+
v.setAttribute('x1', x);
|
|
35
|
+
v.setAttribute('x2', x);
|
|
36
|
+
v.setAttribute('y1', '0');
|
|
37
|
+
v.setAttribute('y2', '640');
|
|
38
|
+
|
|
39
|
+
// Calculate real coordinates using inverse transformation
|
|
40
|
+
const matrix = {"a":177.77777777777777,"c":0,"e":297.77777777777777,"b":0,"d":-177.77777777777777,"f":328.8888888888889};
|
|
41
|
+
// Manually invert and apply the affine transform
|
|
42
|
+
// Since we only use translate and scale, we can directly compute:
|
|
43
|
+
// x' = (x - tx) / sx
|
|
44
|
+
// y' = (y - ty) / sy
|
|
45
|
+
const sx = matrix.a;
|
|
46
|
+
const sy = matrix.d;
|
|
47
|
+
const tx = matrix.e;
|
|
48
|
+
const ty = matrix.f;
|
|
49
|
+
const realPoint = {
|
|
50
|
+
x: (x - tx) / sx,
|
|
51
|
+
y: (y - ty) / sy // Flip y back since we used negative scale
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
coords.textContent = `(${realPoint.x.toFixed(2)}, ${realPoint.y.toFixed(2)})`;
|
|
55
|
+
coords.setAttribute('x', (x + 5).toString());
|
|
56
|
+
coords.setAttribute('y', (y - 5).toString());
|
|
57
|
+
});
|
|
58
|
+
document.currentScript.parentElement.addEventListener('mouseleave', () => {
|
|
59
|
+
document.currentScript.parentElement.getElementById('crosshair').style.display = 'none';
|
|
60
|
+
});
|
|
61
|
+
]]></script></svg>
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
<svg width="640" height="640" viewBox="0 0 640 640" xmlns="http://www.w3.org/2000/svg"><rect width="100%" height="100%" fill="white"/><g><polyline data-points="2.52,1 -0.9,0.7999999999999999" data-type="line" data-label="" points="476.7266775777414,259.0507364975451 163.27332242225856,277.3813420621932" fill="none" stroke="hsl(248, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="2.5200000000000005,1 2.7200000000000006,1 2.7200000000000006,3.3900000000000006 -1.1,3.3900000000000006 -1.1,0.7999999999999999 -0.9,0.7999999999999999" data-type="line" data-label="" points="476.7266775777414,259.0507364975451 495.0572831423895,259.0507364975451 495.0572831423895,40 144.94271685761043,40 144.94271685761043,277.3813420621932 163.27332242225856,277.3813420621932" fill="none" stroke="purple" stroke-width="1px"/></g><g><rect data-type="rect" data-label="schematic_component_0" data-x="0" data-y="0" x="163.27332242225856" y="121.57119476268417" width="164.97545008183306" height="458.26513911620293" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.010910714285714287"/></g><g><rect data-type="rect" data-label="schematic_component_1" data-x="2" data-y="1.0699999999999998" x="381.40752864157116" y="221.4729950900164" width="95.31914893617022" height="62.324058919803605" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.010910714285714287"/></g><g><rect data-type="rect" data-label="part-number" data-x="0.15999999999999992" data-y="-2.63" x="199.93453355155478" y="583.5024549918166" width="120.98199672667755" height="16.49754500818335" fill="rgba(160, 0, 220, 0.14)" stroke="black" stroke-width="0.010910714285714287"/></g><g><rect data-type="rect" data-label="U1" data-x="-0.38" data-y="2.615" x="194.43535188216038" y="99.57446808510645" width="32.99509001636659" height="22.91325695581014" fill="rgba(160, 0, 220, 0.14)" stroke="black" stroke-width="0.010910714285714287"/></g><g><rect data-type="rect" data-label="netId: .LED1 > port.right to .U1 > .pin20
|
|
2
|
+
globalConnNetId: connectivity_net0" data-x="2.6200000000000006" data-y="0.775" x="476.7266775777414" y="259.0507364975451" width="18.330605564648124" height="41.243862520458265" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.010910714285714287"/></g><g><circle data-type="point" data-label="U1.1
|
|
3
|
+
x+" data-x="0.9" data-y="1.2" cx="328.2487725040916" cy="240.72013093289695" r="3" fill="hsl(319, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.2
|
|
4
|
+
x+" data-x="0.9" data-y="0.3999999999999999" cx="328.2487725040916" cy="314.04255319148945" r="3" fill="hsl(320, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.3
|
|
5
|
+
x+" data-x="0.9" data-y="0.5999999999999999" cx="328.2487725040916" cy="295.7119476268413" r="3" fill="hsl(321, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.4
|
|
6
|
+
x-" data-x="-0.9" data-y="0.3999999999999999" cx="163.27332242225856" cy="314.04255319148945" r="3" fill="hsl(322, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.5
|
|
7
|
+
x+" data-x="0.9" data-y="0.9999999999999998" cx="328.2487725040916" cy="259.0507364975451" r="3" fill="hsl(323, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.6
|
|
8
|
+
x+" data-x="0.9" data-y="-0.19999999999999996" cx="328.2487725040916" cy="369.03436988543376" r="3" fill="hsl(324, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.7
|
|
9
|
+
x-" data-x="-0.9" data-y="-0.7999999999999998" cx="163.27332242225856" cy="424.0261865793781" r="3" fill="hsl(325, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.9
|
|
10
|
+
x+" data-x="0.9" data-y="0.19999999999999996" cx="328.2487725040916" cy="332.3731587561375" r="3" fill="hsl(327, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.10
|
|
11
|
+
x+" data-x="0.9" data-y="0" cx="328.2487725040916" cy="350.70376432078564" r="3" fill="hsl(217, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.11
|
|
12
|
+
x+" data-x="0.9" data-y="0.7999999999999998" cx="328.2487725040916" cy="277.3813420621932" r="3" fill="hsl(218, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.12
|
|
13
|
+
x+" data-x="0.9" data-y="-1.2" cx="328.2487725040916" cy="460.6873977086743" r="3" fill="hsl(219, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.13
|
|
14
|
+
x+" data-x="0.9" data-y="-1" cx="328.2487725040916" cy="442.3567921440262" r="3" fill="hsl(220, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.14
|
|
15
|
+
x+" data-x="0.9" data-y="-0.7999999999999999" cx="328.2487725040916" cy="424.0261865793781" r="3" fill="hsl(221, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.15
|
|
16
|
+
x-" data-x="-0.9" data-y="1" cx="163.27332242225856" cy="259.0507364975451" r="3" fill="hsl(222, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.16
|
|
17
|
+
x-" data-x="-0.9" data-y="1.2" cx="163.27332242225856" cy="240.72013093289695" r="3" fill="hsl(223, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.17
|
|
18
|
+
x-" data-x="-0.9" data-y="0.5999999999999999" cx="163.27332242225856" cy="295.7119476268413" r="3" fill="hsl(224, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.18
|
|
19
|
+
x-" data-x="-0.9" data-y="-0.9999999999999998" cx="163.27332242225856" cy="442.3567921440262" r="3" fill="hsl(225, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.19
|
|
20
|
+
x-" data-x="-0.9" data-y="-0.19999999999999996" cx="163.27332242225856" cy="369.03436988543376" r="3" fill="hsl(226, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.20
|
|
21
|
+
x-" data-x="-0.9" data-y="0.7999999999999999" cx="163.27332242225856" cy="277.3813420621932" r="3" fill="hsl(248, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.21
|
|
22
|
+
x-" data-x="-0.9" data-y="-1.2" cx="163.27332242225856" cy="460.6873977086743" r="3" fill="hsl(249, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.22
|
|
23
|
+
x+" data-x="0.9" data-y="-0.5999999999999999" cx="328.2487725040916" cy="405.69558101472995" r="3" fill="hsl(250, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.23
|
|
24
|
+
x+" data-x="0.9" data-y="-0.3999999999999999" cx="328.2487725040916" cy="387.36497545008183" r="3" fill="hsl(251, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.25
|
|
25
|
+
x-" data-x="-0.9" data-y="-0.5999999999999999" cx="163.27332242225856" cy="405.69558101472995" r="3" fill="hsl(253, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.26
|
|
26
|
+
x-" data-x="-0.9" data-y="-0.3999999999999999" cx="163.27332242225856" cy="387.36497545008183" r="3" fill="hsl(254, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.27
|
|
27
|
+
x-" data-x="-0.9" data-y="0.19999999999999996" cx="163.27332242225856" cy="332.3731587561375" r="3" fill="hsl(255, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.28
|
|
28
|
+
x-" data-x="-0.9" data-y="0" cx="163.27332242225856" cy="350.70376432078564" r="3" fill="hsl(256, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="LED1.1
|
|
29
|
+
x-" data-x="1.48" data-y="1" cx="381.40752864157116" cy="259.0507364975451" r="3" fill="hsl(57, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="LED1.2
|
|
30
|
+
x+" data-x="2.52" data-y="1" cx="476.7266775777414" cy="259.0507364975451" r="3" fill="hsl(58, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="anchorPoint
|
|
31
|
+
orientation: y-" data-x="2.6200000000000006" data-y="1" cx="485.8919803600654" cy="259.0507364975451" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g id="crosshair" style="display: none"><line id="crosshair-h" y1="0" y2="640" stroke="#666" stroke-width="0.5"/><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></g><script><![CDATA[
|
|
32
|
+
document.currentScript.parentElement.addEventListener('mousemove', (e) => {
|
|
33
|
+
const svg = e.currentTarget;
|
|
34
|
+
const rect = svg.getBoundingClientRect();
|
|
35
|
+
const x = e.clientX - rect.left;
|
|
36
|
+
const y = e.clientY - rect.top;
|
|
37
|
+
const crosshair = svg.getElementById('crosshair');
|
|
38
|
+
const h = svg.getElementById('crosshair-h');
|
|
39
|
+
const v = svg.getElementById('crosshair-v');
|
|
40
|
+
const coords = svg.getElementById('coordinates');
|
|
41
|
+
|
|
42
|
+
crosshair.style.display = 'block';
|
|
43
|
+
h.setAttribute('x1', '0');
|
|
44
|
+
h.setAttribute('x2', '640');
|
|
45
|
+
h.setAttribute('y1', y);
|
|
46
|
+
h.setAttribute('y2', y);
|
|
47
|
+
v.setAttribute('x1', x);
|
|
48
|
+
v.setAttribute('x2', x);
|
|
49
|
+
v.setAttribute('y1', '0');
|
|
50
|
+
v.setAttribute('y2', '640');
|
|
51
|
+
|
|
52
|
+
// Calculate real coordinates using inverse transformation
|
|
53
|
+
const matrix = {"a":91.65302782324058,"c":0,"e":245.7610474631751,"b":0,"d":-91.65302782324058,"f":350.70376432078564};
|
|
54
|
+
// Manually invert and apply the affine transform
|
|
55
|
+
// Since we only use translate and scale, we can directly compute:
|
|
56
|
+
// x' = (x - tx) / sx
|
|
57
|
+
// y' = (y - ty) / sy
|
|
58
|
+
const sx = matrix.a;
|
|
59
|
+
const sy = matrix.d;
|
|
60
|
+
const tx = matrix.e;
|
|
61
|
+
const ty = matrix.f;
|
|
62
|
+
const realPoint = {
|
|
63
|
+
x: (x - tx) / sx,
|
|
64
|
+
y: (y - ty) / sy // Flip y back since we used negative scale
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
coords.textContent = `(${realPoint.x.toFixed(2)}, ${realPoint.y.toFixed(2)})`;
|
|
68
|
+
coords.setAttribute('x', (x + 5).toString());
|
|
69
|
+
coords.setAttribute('y', (y - 5).toString());
|
|
70
|
+
});
|
|
71
|
+
document.currentScript.parentElement.addEventListener('mouseleave', () => {
|
|
72
|
+
document.currentScript.parentElement.getElementById('crosshair').style.display = 'none';
|
|
73
|
+
});
|
|
74
|
+
]]></script></svg>
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
{
|
|
2
|
+
"chips": [
|
|
3
|
+
{
|
|
4
|
+
"chipId": "schematic_component_0",
|
|
5
|
+
"center": {
|
|
6
|
+
"x": -0.95,
|
|
7
|
+
"y": 0.825
|
|
8
|
+
},
|
|
9
|
+
"width": 0.6000000000000001,
|
|
10
|
+
"height": 0.6800000000000002,
|
|
11
|
+
"pins": [
|
|
12
|
+
{
|
|
13
|
+
"pinId": "R1.1",
|
|
14
|
+
"x": -1.25,
|
|
15
|
+
"y": 0.825,
|
|
16
|
+
"_facingDirection": "x-"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"pinId": "R1.2",
|
|
20
|
+
"x": -0.6499999999999999,
|
|
21
|
+
"y": 0.825,
|
|
22
|
+
"_facingDirection": "x+"
|
|
23
|
+
}
|
|
24
|
+
]
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"chipId": "schematic_component_1",
|
|
28
|
+
"center": {
|
|
29
|
+
"x": 0.95,
|
|
30
|
+
"y": 0.825
|
|
31
|
+
},
|
|
32
|
+
"width": 0.6000000000000001,
|
|
33
|
+
"height": 0.6800000000000002,
|
|
34
|
+
"pins": [
|
|
35
|
+
{
|
|
36
|
+
"pinId": "R2.1",
|
|
37
|
+
"x": 0.6499999999999999,
|
|
38
|
+
"y": 0.825,
|
|
39
|
+
"_facingDirection": "x-"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"pinId": "R2.2",
|
|
43
|
+
"x": 1.25,
|
|
44
|
+
"y": 0.825,
|
|
45
|
+
"_facingDirection": "x+"
|
|
46
|
+
}
|
|
47
|
+
]
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"chipId": "schematic_component_2",
|
|
51
|
+
"center": {
|
|
52
|
+
"x": -0.95,
|
|
53
|
+
"y": -0.825
|
|
54
|
+
},
|
|
55
|
+
"width": 0.6000000000000001,
|
|
56
|
+
"height": 0.6800000000000002,
|
|
57
|
+
"pins": [
|
|
58
|
+
{
|
|
59
|
+
"pinId": "R3.1",
|
|
60
|
+
"x": -1.25,
|
|
61
|
+
"y": -0.825,
|
|
62
|
+
"_facingDirection": "x-"
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"pinId": "R3.2",
|
|
66
|
+
"x": -0.6499999999999999,
|
|
67
|
+
"y": -0.825,
|
|
68
|
+
"_facingDirection": "x+"
|
|
69
|
+
}
|
|
70
|
+
]
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"chipId": "schematic_component_3",
|
|
74
|
+
"center": {
|
|
75
|
+
"x": 0.95,
|
|
76
|
+
"y": -0.825
|
|
77
|
+
},
|
|
78
|
+
"width": 0.9,
|
|
79
|
+
"height": 0.5557574704999997,
|
|
80
|
+
"pins": [
|
|
81
|
+
{
|
|
82
|
+
"pinId": "J1.1",
|
|
83
|
+
"x": 0.49999999999999994,
|
|
84
|
+
"y": -0.725
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"pinId": "J1.2",
|
|
88
|
+
"x": 0.95,
|
|
89
|
+
"y": -1.1028787352499998
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"pinId": "J1.3",
|
|
93
|
+
"x": 1.4,
|
|
94
|
+
"y": -0.725
|
|
95
|
+
}
|
|
96
|
+
]
|
|
97
|
+
}
|
|
98
|
+
],
|
|
99
|
+
"directConnections": [
|
|
100
|
+
{
|
|
101
|
+
"pinIds": [
|
|
102
|
+
"R2.1",
|
|
103
|
+
"R3.2"
|
|
104
|
+
],
|
|
105
|
+
"netId": ".R2 > .pin1 to .R3 > .pin2"
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
"pinIds": [
|
|
109
|
+
"R2.2",
|
|
110
|
+
"R3.1"
|
|
111
|
+
],
|
|
112
|
+
"netId": ".R2 > .pin2 to .R3 > .pin1"
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
"pinIds": [
|
|
116
|
+
"J1.1",
|
|
117
|
+
"R1.1"
|
|
118
|
+
],
|
|
119
|
+
"netId": ".J1 > .pin1 to .R1 > .pin1"
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
"pinIds": [
|
|
123
|
+
"J1.3",
|
|
124
|
+
"R1.2"
|
|
125
|
+
],
|
|
126
|
+
"netId": ".J1 > .pin3 to .R1 > .pin2"
|
|
127
|
+
}
|
|
128
|
+
],
|
|
129
|
+
"netConnections": [],
|
|
130
|
+
"textBoxes": [],
|
|
131
|
+
"availableNetLabelOrientations": {},
|
|
132
|
+
"maxMspPairDistance": 5
|
|
133
|
+
}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
{
|
|
2
|
+
"chips": [
|
|
3
|
+
{
|
|
4
|
+
"chipId": "schematic_component_0",
|
|
5
|
+
"center": {
|
|
6
|
+
"x": 0,
|
|
7
|
+
"y": 0
|
|
8
|
+
},
|
|
9
|
+
"width": 1.8,
|
|
10
|
+
"height": 5,
|
|
11
|
+
"pins": [
|
|
12
|
+
{
|
|
13
|
+
"pinId": "U1.1",
|
|
14
|
+
"x": 0.9,
|
|
15
|
+
"y": 1.2
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"pinId": "U1.2",
|
|
19
|
+
"x": 0.9,
|
|
20
|
+
"y": 0.3999999999999999
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"pinId": "U1.3",
|
|
24
|
+
"x": 0.9,
|
|
25
|
+
"y": 0.5999999999999999
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"pinId": "U1.4",
|
|
29
|
+
"x": -0.9,
|
|
30
|
+
"y": 0.3999999999999999
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"pinId": "U1.5",
|
|
34
|
+
"x": 0.9,
|
|
35
|
+
"y": 0.9999999999999998
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"pinId": "U1.6",
|
|
39
|
+
"x": 0.9,
|
|
40
|
+
"y": -0.19999999999999996
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"pinId": "U1.7",
|
|
44
|
+
"x": -0.9,
|
|
45
|
+
"y": -0.7999999999999998
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"pinId": "U1.9",
|
|
49
|
+
"x": 0.9,
|
|
50
|
+
"y": 0.19999999999999996
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"pinId": "U1.10",
|
|
54
|
+
"x": 0.9,
|
|
55
|
+
"y": 0
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"pinId": "U1.11",
|
|
59
|
+
"x": 0.9,
|
|
60
|
+
"y": 0.7999999999999998
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"pinId": "U1.12",
|
|
64
|
+
"x": 0.9,
|
|
65
|
+
"y": -1.2
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"pinId": "U1.13",
|
|
69
|
+
"x": 0.9,
|
|
70
|
+
"y": -1
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"pinId": "U1.14",
|
|
74
|
+
"x": 0.9,
|
|
75
|
+
"y": -0.7999999999999999
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"pinId": "U1.15",
|
|
79
|
+
"x": -0.9,
|
|
80
|
+
"y": 1
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"pinId": "U1.16",
|
|
84
|
+
"x": -0.9,
|
|
85
|
+
"y": 1.2
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"pinId": "U1.17",
|
|
89
|
+
"x": -0.9,
|
|
90
|
+
"y": 0.5999999999999999
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"pinId": "U1.18",
|
|
94
|
+
"x": -0.9,
|
|
95
|
+
"y": -0.9999999999999998
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"pinId": "U1.19",
|
|
99
|
+
"x": -0.9,
|
|
100
|
+
"y": -0.19999999999999996
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
"pinId": "U1.20",
|
|
104
|
+
"x": -0.9,
|
|
105
|
+
"y": 0.7999999999999999
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
"pinId": "U1.21",
|
|
109
|
+
"x": -0.9,
|
|
110
|
+
"y": -1.2
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"pinId": "U1.22",
|
|
114
|
+
"x": 0.9,
|
|
115
|
+
"y": -0.5999999999999999
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"pinId": "U1.23",
|
|
119
|
+
"x": 0.9,
|
|
120
|
+
"y": -0.3999999999999999
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
"pinId": "U1.25",
|
|
124
|
+
"x": -0.9,
|
|
125
|
+
"y": -0.5999999999999999
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
"pinId": "U1.26",
|
|
129
|
+
"x": -0.9,
|
|
130
|
+
"y": -0.3999999999999999
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
"pinId": "U1.27",
|
|
134
|
+
"x": -0.9,
|
|
135
|
+
"y": 0.19999999999999996
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
"pinId": "U1.28",
|
|
139
|
+
"x": -0.9,
|
|
140
|
+
"y": 0
|
|
141
|
+
}
|
|
142
|
+
]
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
"chipId": "schematic_component_1",
|
|
146
|
+
"center": {
|
|
147
|
+
"x": 2,
|
|
148
|
+
"y": 1.0699999999999998
|
|
149
|
+
},
|
|
150
|
+
"width": 1.04,
|
|
151
|
+
"height": 0.6799999999999999,
|
|
152
|
+
"pins": [
|
|
153
|
+
{
|
|
154
|
+
"pinId": "LED1.1",
|
|
155
|
+
"x": 1.48,
|
|
156
|
+
"y": 1,
|
|
157
|
+
"_facingDirection": "x-"
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
"pinId": "LED1.2",
|
|
161
|
+
"x": 2.52,
|
|
162
|
+
"y": 1,
|
|
163
|
+
"_facingDirection": "x+"
|
|
164
|
+
}
|
|
165
|
+
]
|
|
166
|
+
}
|
|
167
|
+
],
|
|
168
|
+
"directConnections": [
|
|
169
|
+
{
|
|
170
|
+
"pinIds": [
|
|
171
|
+
"LED1.2",
|
|
172
|
+
"U1.20"
|
|
173
|
+
],
|
|
174
|
+
"netId": ".LED1 > port.right to .U1 > .pin20"
|
|
175
|
+
}
|
|
176
|
+
],
|
|
177
|
+
"netConnections": [],
|
|
178
|
+
"textBoxes": [
|
|
179
|
+
{
|
|
180
|
+
"chipId": "schematic_component_0",
|
|
181
|
+
"center": {
|
|
182
|
+
"x": 0.15999999999999992,
|
|
183
|
+
"y": -2.63
|
|
184
|
+
},
|
|
185
|
+
"width": 1.3199999999999998,
|
|
186
|
+
"height": 0.17999999999999972,
|
|
187
|
+
"text": "part-number"
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
"chipId": "schematic_component_0",
|
|
191
|
+
"center": {
|
|
192
|
+
"x": -0.38,
|
|
193
|
+
"y": 2.615
|
|
194
|
+
},
|
|
195
|
+
"width": 0.36000000000000004,
|
|
196
|
+
"height": 0.24999999999999956,
|
|
197
|
+
"text": "U1"
|
|
198
|
+
}
|
|
199
|
+
],
|
|
200
|
+
"availableNetLabelOrientations": {},
|
|
201
|
+
"maxMspPairDistance": 5
|
|
202
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { expect, test } from "bun:test"
|
|
2
|
+
import { SchematicTracePipelineSolver } from "lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver"
|
|
3
|
+
import "tests/fixtures/matcher"
|
|
4
|
+
import inputProblem from "./assets/repro47-endpoint-obstacle-detour.input.json"
|
|
5
|
+
|
|
6
|
+
test("repro47: endpoint obstacle detours route around nearby components", () => {
|
|
7
|
+
const solver = new SchematicTracePipelineSolver(inputProblem as any)
|
|
8
|
+
|
|
9
|
+
solver.solve()
|
|
10
|
+
|
|
11
|
+
expect(
|
|
12
|
+
solver
|
|
13
|
+
.schematicTraceLinesSolver!.failedConnectionPairs.map(
|
|
14
|
+
(pair) => pair.mspPairId,
|
|
15
|
+
)
|
|
16
|
+
.sort(),
|
|
17
|
+
).toEqual([])
|
|
18
|
+
expect(solver).toMatchSolverSnapshot(import.meta.path)
|
|
19
|
+
})
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { expect, test } from "bun:test"
|
|
2
|
+
import { SchematicTracePipelineSolver } from "lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver"
|
|
3
|
+
import "tests/fixtures/matcher"
|
|
4
|
+
import inputProblem from "./assets/repro5-escape-padded-text-obstacles.input.json"
|
|
5
|
+
|
|
6
|
+
test("repro5: route escapes past padded text obstacles", () => {
|
|
7
|
+
const solver = new SchematicTracePipelineSolver(inputProblem as any)
|
|
8
|
+
|
|
9
|
+
solver.solve()
|
|
10
|
+
|
|
11
|
+
expect(
|
|
12
|
+
solver.schematicTraceLinesSolver!.failedConnectionPairs.map(
|
|
13
|
+
(pair) => pair.mspPairId,
|
|
14
|
+
),
|
|
15
|
+
).toEqual([])
|
|
16
|
+
expect(solver).toMatchSolverSnapshot(import.meta.path)
|
|
17
|
+
})
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { expect, test } from "bun:test"
|
|
2
|
+
import { candidateMidsFromSet } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/mid"
|
|
3
|
+
import type { ObstacleRect } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/rect"
|
|
4
|
+
|
|
5
|
+
test("candidate mids include clearance beyond an open obstacle side", () => {
|
|
6
|
+
const previousObstacle: ObstacleRect = {
|
|
7
|
+
kind: "chip",
|
|
8
|
+
chipId: "U1",
|
|
9
|
+
minX: -0.9,
|
|
10
|
+
maxX: 0.9,
|
|
11
|
+
minY: -2.5,
|
|
12
|
+
maxY: 2.5,
|
|
13
|
+
}
|
|
14
|
+
const collidingObstacle: ObstacleRect = {
|
|
15
|
+
kind: "text_box",
|
|
16
|
+
textBox: {
|
|
17
|
+
center: { x: -0.38, y: 2.615 },
|
|
18
|
+
width: 0.36,
|
|
19
|
+
height: 0.25,
|
|
20
|
+
text: "U1",
|
|
21
|
+
},
|
|
22
|
+
minX: -1.01,
|
|
23
|
+
maxX: 0.25,
|
|
24
|
+
minY: 2.04,
|
|
25
|
+
maxY: 3.19,
|
|
26
|
+
}
|
|
27
|
+
const aabb = { minX: -0.9, maxX: 2.52, minY: 0.8, maxY: 1 }
|
|
28
|
+
const collisionRects = new Set([previousObstacle])
|
|
29
|
+
|
|
30
|
+
expect(
|
|
31
|
+
candidateMidsFromSet("y", collidingObstacle, collisionRects, aabb),
|
|
32
|
+
).toEqual([1.42])
|
|
33
|
+
|
|
34
|
+
expect(
|
|
35
|
+
candidateMidsFromSet("y", collidingObstacle, collisionRects, aabb, {
|
|
36
|
+
allowOpenSideCandidates: true,
|
|
37
|
+
}),
|
|
38
|
+
).toEqual([1.42, 3.39])
|
|
39
|
+
})
|
package/tests/solvers/SchematicTraceSingleLineSolver2/generate-endpoint-collision-detours.test.ts
CHANGED
|
@@ -36,3 +36,40 @@ test("endpoint collision detours preserve both endpoint anchors", () => {
|
|
|
36
36
|
),
|
|
37
37
|
).toBe(true)
|
|
38
38
|
})
|
|
39
|
+
|
|
40
|
+
test("endpoint collision detours preserve the remainder of a U-shaped path", () => {
|
|
41
|
+
const path = [
|
|
42
|
+
{ x: 0, y: 1 },
|
|
43
|
+
{ x: 2, y: 1 },
|
|
44
|
+
{ x: 2, y: -1 },
|
|
45
|
+
{ x: 4, y: -1 },
|
|
46
|
+
]
|
|
47
|
+
|
|
48
|
+
const obstacle = {
|
|
49
|
+
minX: 1,
|
|
50
|
+
maxX: 3,
|
|
51
|
+
minY: 0,
|
|
52
|
+
maxY: 2,
|
|
53
|
+
kind: "chip" as const,
|
|
54
|
+
chipId: "U1",
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
for (const collidingSegmentIndex of [0, 2]) {
|
|
58
|
+
const detours = generateEndpointCollisionDetours({
|
|
59
|
+
path,
|
|
60
|
+
collidingSegmentIndex,
|
|
61
|
+
obstacle,
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
expect(detours.length).toBeGreaterThan(0)
|
|
65
|
+
const preservedSegment =
|
|
66
|
+
collidingSegmentIndex === 0 ? path.slice(-2) : path.slice(0, 2)
|
|
67
|
+
for (const detour of detours) {
|
|
68
|
+
expect(detour[0]).toEqual(path[0])
|
|
69
|
+
expect(detour.at(-1)).toEqual(path.at(-1))
|
|
70
|
+
expect(
|
|
71
|
+
collidingSegmentIndex === 0 ? detour.slice(-2) : detour.slice(0, 2),
|
|
72
|
+
).toEqual(preservedSegment)
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
})
|