@tscircuit/schematic-trace-solver 0.0.88 → 0.0.90
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 +4 -0
- package/dist/index.js +112 -29
- package/lib/solvers/Example28Solver/reroute.ts +10 -0
- package/lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/SchematicTraceSingleLineSolver2.ts +116 -5
- package/lib/testing/PipelineStageDebugRunner.ts +21 -4
- package/package.json +1 -1
- package/tests/bug-reports/bug-report-20260706T213649Z/__snapshots__/bug-report-20260706T213649Z.snap.svg +386 -0
- package/tests/bug-reports/bug-report-20260706T213649Z/bug-report-20260706T213649Z.json +1471 -0
- package/tests/bug-reports/bug-report-20260706T213649Z/bug-report-20260706T213649Z.test.ts +12 -0
- package/tests/bug-reports/bug-report-20260706T220324Z/__snapshots__/bug-report-20260706T220324Z.snap.svg +22 -22
- package/tests/bug-reports/bug-report-20260707T020342Z/__snapshots__/bug-report-20260707T020342Z.snap.svg +20 -22
- package/tests/bug-reports/bug-report-20260707T092615Z/__snapshots__/bug-report-20260707T092615Z.snap.svg +251 -2097
- package/tests/bug-reports/bug-report-20260707T134549Z/__snapshots__/bug-report-20260707T134549Z.snap.svg +123 -856
- package/tests/bug-reports/bug-report-20260707T134722Z/__snapshots__/bug-report-20260707T134722Z.snap.svg +72 -274
- package/tests/bug-reports/bug-report-20260707T140410Z/__snapshots__/bug-report-20260707T140410Z.snap.svg +153 -949
- package/tests/bug-reports/bug-report-20260707T141025Z/__snapshots__/bug-report-20260707T141025Z.snap.svg +66 -217
- package/tests/bug-reports/bug-report-20260707T141421Z/__snapshots__/bug-report-20260707T141421Z.snap.svg +111 -612
- package/tests/bug-reports/bug-report-20260707T141421Z/bug-report-20260707T141421Z.test.ts +11 -0
- package/tests/examples/__snapshots__/example03.snap.svg +44 -44
- package/tests/examples/__snapshots__/example32.snap.svg +3 -3
- package/tests/examples/__snapshots__/example42.snap.svg +1 -1
- package/tests/repros/__snapshots__/repro-atmega328p-fault-pullup.snap.svg +87 -283
- package/tests/repros/__snapshots__/repro-atmega328p-missing-gnd-netlabel.snap.svg +117 -469
package/dist/index.d.ts
CHANGED
|
@@ -170,6 +170,7 @@ declare class SchematicTraceSingleLineSolver2 extends BaseSolver {
|
|
|
170
170
|
chipMap: Record<string, InputChip>;
|
|
171
171
|
obstacles: ObstacleRect[];
|
|
172
172
|
textObstacles: Set<ObstacleRect>;
|
|
173
|
+
endpointTextObstacles: Set<ObstacleRect>;
|
|
173
174
|
aabb: {
|
|
174
175
|
minX: number;
|
|
175
176
|
maxX: number;
|
|
@@ -192,6 +193,9 @@ declare class SchematicTraceSingleLineSolver2 extends BaseSolver {
|
|
|
192
193
|
private getNetLabelHeightForConnectionPair;
|
|
193
194
|
private axisOfSegment;
|
|
194
195
|
private pathLength;
|
|
196
|
+
private getPinBandPenalty;
|
|
197
|
+
private pathCost;
|
|
198
|
+
private isSegmentOutsidePinBand;
|
|
195
199
|
_step(): void;
|
|
196
200
|
visualize(): GraphicsObject;
|
|
197
201
|
}
|
package/dist/index.js
CHANGED
|
@@ -854,6 +854,7 @@ var SchematicTraceSingleLineSolver2 = class extends BaseSolver {
|
|
|
854
854
|
chipMap;
|
|
855
855
|
obstacles;
|
|
856
856
|
textObstacles;
|
|
857
|
+
endpointTextObstacles;
|
|
857
858
|
aabb;
|
|
858
859
|
baseElbow;
|
|
859
860
|
solvedTracePath = null;
|
|
@@ -877,6 +878,12 @@ var SchematicTraceSingleLineSolver2 = class extends BaseSolver {
|
|
|
877
878
|
this.textObstacles = new Set(
|
|
878
879
|
this.obstacles.filter((r) => r.kind === "text_box")
|
|
879
880
|
);
|
|
881
|
+
const endpointChipIds = new Set(this.pins.map((pin) => pin.chipId));
|
|
882
|
+
this.endpointTextObstacles = new Set(
|
|
883
|
+
endpointChipIds.size > 1 ? this.obstacles.filter(
|
|
884
|
+
(r) => r.kind === "text_box" && r.textBox.chipId !== void 0 && endpointChipIds.has(r.textBox.chipId)
|
|
885
|
+
) : []
|
|
886
|
+
);
|
|
880
887
|
const [pin1, pin2] = this.pins;
|
|
881
888
|
this.baseElbow = calculateElbow(
|
|
882
889
|
{
|
|
@@ -985,6 +992,31 @@ var SchematicTraceSingleLineSolver2 = class extends BaseSolver {
|
|
|
985
992
|
}
|
|
986
993
|
return sum;
|
|
987
994
|
}
|
|
995
|
+
getPinBandPenalty(path) {
|
|
996
|
+
let penalty = 0;
|
|
997
|
+
for (let i = 1; i < path.length - 2; i++) {
|
|
998
|
+
const a = path[i];
|
|
999
|
+
const b = path[i + 1];
|
|
1000
|
+
if (isHorizontal(a, b) && a.y > this.aabb.minY && a.y < this.aabb.maxY) {
|
|
1001
|
+
penalty += 10;
|
|
1002
|
+
} else if (isVertical(a, b) && a.x > this.aabb.minX && a.x < this.aabb.maxX) {
|
|
1003
|
+
penalty += 10;
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
return penalty;
|
|
1007
|
+
}
|
|
1008
|
+
pathCost(path) {
|
|
1009
|
+
return this.pathLength(path) + this.getPinBandPenalty(path);
|
|
1010
|
+
}
|
|
1011
|
+
isSegmentOutsidePinBand(a, b) {
|
|
1012
|
+
if (isHorizontal(a, b)) {
|
|
1013
|
+
return a.y <= this.aabb.minY || a.y >= this.aabb.maxY;
|
|
1014
|
+
}
|
|
1015
|
+
if (isVertical(a, b)) {
|
|
1016
|
+
return a.x <= this.aabb.minX || a.x >= this.aabb.maxX;
|
|
1017
|
+
}
|
|
1018
|
+
return false;
|
|
1019
|
+
}
|
|
988
1020
|
_step() {
|
|
989
1021
|
if (this.solvedTracePath) {
|
|
990
1022
|
this.solved = true;
|
|
@@ -1000,10 +1032,17 @@ var SchematicTraceSingleLineSolver2 = class extends BaseSolver {
|
|
|
1000
1032
|
const [PA, PB] = this.pins;
|
|
1001
1033
|
const collision = findFirstCollision(path, this.obstacles, {
|
|
1002
1034
|
excludeRectsForSegment: (segIndex2) => {
|
|
1003
|
-
const
|
|
1004
|
-
if (segIndex2 === 0 || segIndex2 ===
|
|
1035
|
+
const lastSegIndex2 = path.length - 2;
|
|
1036
|
+
if (segIndex2 === 0 || segIndex2 === lastSegIndex2) {
|
|
1005
1037
|
return this.textObstacles;
|
|
1006
1038
|
}
|
|
1039
|
+
const adjacentEndpointSegIndex = segIndex2 === 1 ? 2 : segIndex2 === lastSegIndex2 - 1 ? lastSegIndex2 - 2 : null;
|
|
1040
|
+
if (adjacentEndpointSegIndex !== null && adjacentEndpointSegIndex >= 0 && adjacentEndpointSegIndex < lastSegIndex2 && this.isSegmentOutsidePinBand(
|
|
1041
|
+
path[adjacentEndpointSegIndex],
|
|
1042
|
+
path[adjacentEndpointSegIndex + 1]
|
|
1043
|
+
)) {
|
|
1044
|
+
return this.endpointTextObstacles;
|
|
1045
|
+
}
|
|
1007
1046
|
return /* @__PURE__ */ new Set();
|
|
1008
1047
|
}
|
|
1009
1048
|
});
|
|
@@ -1018,6 +1057,7 @@ var SchematicTraceSingleLineSolver2 = class extends BaseSolver {
|
|
|
1018
1057
|
}
|
|
1019
1058
|
return;
|
|
1020
1059
|
}
|
|
1060
|
+
const originalSegIndex = collision.segIndex;
|
|
1021
1061
|
let { segIndex, rect } = collision;
|
|
1022
1062
|
const isFirstSegment = segIndex === 0;
|
|
1023
1063
|
const isLastSegment = segIndex === path.length - 2;
|
|
@@ -1050,16 +1090,51 @@ var SchematicTraceSingleLineSolver2 = class extends BaseSolver {
|
|
|
1050
1090
|
candidates.push(...mids);
|
|
1051
1091
|
}
|
|
1052
1092
|
const newStates = [];
|
|
1053
|
-
|
|
1054
|
-
const newPath = shiftSegmentOrth(
|
|
1055
|
-
|
|
1093
|
+
const addShiftedCandidate = (candidateSegIndex, candidateAxis, coord) => {
|
|
1094
|
+
const newPath = shiftSegmentOrth(
|
|
1095
|
+
path,
|
|
1096
|
+
candidateSegIndex,
|
|
1097
|
+
candidateAxis,
|
|
1098
|
+
coord
|
|
1099
|
+
);
|
|
1100
|
+
if (!newPath) return;
|
|
1056
1101
|
const key = pathKey(newPath);
|
|
1057
|
-
if (this.visited.has(key))
|
|
1102
|
+
if (this.visited.has(key)) return;
|
|
1058
1103
|
this.visited.add(key);
|
|
1059
1104
|
const nextSet = new Set(collisionRects);
|
|
1060
1105
|
nextSet.add(rect);
|
|
1061
|
-
const len = this.
|
|
1106
|
+
const len = this.pathCost(newPath);
|
|
1062
1107
|
newStates.push({ path: newPath, collisionRects: nextSet, len });
|
|
1108
|
+
};
|
|
1109
|
+
for (const coord of candidates) {
|
|
1110
|
+
addShiftedCandidate(segIndex, axis, coord);
|
|
1111
|
+
}
|
|
1112
|
+
const lastSegIndex = path.length - 2;
|
|
1113
|
+
const adjacentSegmentIndexes = originalSegIndex === 1 ? [2] : originalSegIndex === lastSegIndex - 1 ? [lastSegIndex - 2] : [];
|
|
1114
|
+
for (const adjacentSegIndex of adjacentSegmentIndexes) {
|
|
1115
|
+
if (adjacentSegIndex < 0 || adjacentSegIndex >= lastSegIndex) continue;
|
|
1116
|
+
const adjacentAxis = this.axisOfSegment(
|
|
1117
|
+
path[adjacentSegIndex],
|
|
1118
|
+
path[adjacentSegIndex + 1]
|
|
1119
|
+
);
|
|
1120
|
+
if (!adjacentAxis || adjacentAxis === axis) continue;
|
|
1121
|
+
const adjacentCandidates = [
|
|
1122
|
+
...midBetweenPointAndRect(adjacentAxis, { x: PA.x, y: PA.y }, rect),
|
|
1123
|
+
...midBetweenPointAndRect(adjacentAxis, { x: PB.x, y: PB.y }, rect)
|
|
1124
|
+
];
|
|
1125
|
+
if (collisionRects.size > 0) {
|
|
1126
|
+
adjacentCandidates.push(
|
|
1127
|
+
...candidateMidsFromSet(
|
|
1128
|
+
adjacentAxis,
|
|
1129
|
+
rect,
|
|
1130
|
+
collisionRects,
|
|
1131
|
+
this.aabb
|
|
1132
|
+
)
|
|
1133
|
+
);
|
|
1134
|
+
}
|
|
1135
|
+
for (const coord of [...new Set(adjacentCandidates)]) {
|
|
1136
|
+
addShiftedCandidate(adjacentSegIndex, adjacentAxis, coord);
|
|
1137
|
+
}
|
|
1063
1138
|
}
|
|
1064
1139
|
newStates.sort((a2, b2) => a2.len - b2.len);
|
|
1065
1140
|
for (const st of newStates) {
|
|
@@ -5419,6 +5494,28 @@ var moveAttachedLabelsToReroutedTrace = ({
|
|
|
5419
5494
|
};
|
|
5420
5495
|
});
|
|
5421
5496
|
|
|
5497
|
+
// lib/solvers/Example28Solver/doesPathRunAlongChipBoundary.ts
|
|
5498
|
+
var doesPathRunAlongChipBoundary = (path, chipObstacles) => {
|
|
5499
|
+
for (let i = 0; i < path.length - 1; i++) {
|
|
5500
|
+
const start = path[i];
|
|
5501
|
+
const end = path[i + 1];
|
|
5502
|
+
for (const obstacle of chipObstacles) {
|
|
5503
|
+
if (!segmentRunsAlongRectBoundary(start, end, obstacle)) continue;
|
|
5504
|
+
if (getSegmentOverlapWithRectSpan(start, end, obstacle) > EPS7) {
|
|
5505
|
+
return true;
|
|
5506
|
+
}
|
|
5507
|
+
}
|
|
5508
|
+
}
|
|
5509
|
+
return false;
|
|
5510
|
+
};
|
|
5511
|
+
var getSegmentOverlapWithRectSpan = (start, end, rect) => {
|
|
5512
|
+
const isVertical4 = Math.abs(start.x - end.x) < EPS7;
|
|
5513
|
+
if (isVertical4) {
|
|
5514
|
+
return Math.min(Math.max(start.y, end.y), rect.maxY) - Math.max(Math.min(start.y, end.y), rect.minY);
|
|
5515
|
+
}
|
|
5516
|
+
return Math.min(Math.max(start.x, end.x), rect.maxX) - Math.max(Math.min(start.x, end.x), rect.minX);
|
|
5517
|
+
};
|
|
5518
|
+
|
|
5422
5519
|
// lib/solvers/Example28Solver/reroute.ts
|
|
5423
5520
|
var LABEL_CLEARANCE = 0.1;
|
|
5424
5521
|
var findBestReroutePath = ({
|
|
@@ -5529,6 +5626,14 @@ var createCandidateResult = ({
|
|
|
5529
5626
|
selected: false
|
|
5530
5627
|
};
|
|
5531
5628
|
}
|
|
5629
|
+
if (doesPathRunAlongChipBoundary(path, chipObstacles)) {
|
|
5630
|
+
return {
|
|
5631
|
+
path,
|
|
5632
|
+
status: "chip-collision",
|
|
5633
|
+
usesHorizontalSegmentPush,
|
|
5634
|
+
selected: false
|
|
5635
|
+
};
|
|
5636
|
+
}
|
|
5532
5637
|
return {
|
|
5533
5638
|
path,
|
|
5534
5639
|
score: scoreTracePath({
|
|
@@ -5792,28 +5897,6 @@ var countCrossingsWithOtherTraces = (params) => {
|
|
|
5792
5897
|
return crossingCount;
|
|
5793
5898
|
};
|
|
5794
5899
|
|
|
5795
|
-
// lib/solvers/Example28Solver/doesPathRunAlongChipBoundary.ts
|
|
5796
|
-
var doesPathRunAlongChipBoundary = (path, chipObstacles) => {
|
|
5797
|
-
for (let i = 0; i < path.length - 1; i++) {
|
|
5798
|
-
const start = path[i];
|
|
5799
|
-
const end = path[i + 1];
|
|
5800
|
-
for (const obstacle of chipObstacles) {
|
|
5801
|
-
if (!segmentRunsAlongRectBoundary(start, end, obstacle)) continue;
|
|
5802
|
-
if (getSegmentOverlapWithRectSpan(start, end, obstacle) > EPS7) {
|
|
5803
|
-
return true;
|
|
5804
|
-
}
|
|
5805
|
-
}
|
|
5806
|
-
}
|
|
5807
|
-
return false;
|
|
5808
|
-
};
|
|
5809
|
-
var getSegmentOverlapWithRectSpan = (start, end, rect) => {
|
|
5810
|
-
const isVertical4 = Math.abs(start.x - end.x) < EPS7;
|
|
5811
|
-
if (isVertical4) {
|
|
5812
|
-
return Math.min(Math.max(start.y, end.y), rect.maxY) - Math.max(Math.min(start.y, end.y), rect.minY);
|
|
5813
|
-
}
|
|
5814
|
-
return Math.min(Math.max(start.x, end.x), rect.maxX) - Math.max(Math.min(start.x, end.x), rect.minX);
|
|
5815
|
-
};
|
|
5816
|
-
|
|
5817
5900
|
// lib/solvers/Example28Solver/scoreSolutionTracePath.ts
|
|
5818
5901
|
var scoreSolutionTracePath = (params) => {
|
|
5819
5902
|
const { traces, outputTraces, chipObstacles } = params;
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
getPathLength,
|
|
15
15
|
isPathCollidingWithChipInterior,
|
|
16
16
|
} from "./geometry"
|
|
17
|
+
import { doesPathRunAlongChipBoundary } from "./doesPathRunAlongChipBoundary"
|
|
17
18
|
import type {
|
|
18
19
|
ChipObstacle,
|
|
19
20
|
RerouteCandidateResult,
|
|
@@ -165,6 +166,15 @@ const createCandidateResult = ({
|
|
|
165
166
|
}
|
|
166
167
|
}
|
|
167
168
|
|
|
169
|
+
if (doesPathRunAlongChipBoundary(path, chipObstacles)) {
|
|
170
|
+
return {
|
|
171
|
+
path,
|
|
172
|
+
status: "chip-collision",
|
|
173
|
+
usesHorizontalSegmentPush,
|
|
174
|
+
selected: false,
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
168
178
|
return {
|
|
169
179
|
path,
|
|
170
180
|
score: scoreTracePath({
|
|
@@ -29,6 +29,7 @@ export class SchematicTraceSingleLineSolver2 extends BaseSolver {
|
|
|
29
29
|
|
|
30
30
|
obstacles: ObstacleRect[]
|
|
31
31
|
textObstacles: Set<ObstacleRect>
|
|
32
|
+
endpointTextObstacles: Set<ObstacleRect>
|
|
32
33
|
aabb: { minX: number; maxX: number; minY: number; maxY: number }
|
|
33
34
|
|
|
34
35
|
baseElbow: Point[]
|
|
@@ -67,6 +68,17 @@ export class SchematicTraceSingleLineSolver2 extends BaseSolver {
|
|
|
67
68
|
this.textObstacles = new Set(
|
|
68
69
|
this.obstacles.filter((r) => r.kind === "text_box"),
|
|
69
70
|
)
|
|
71
|
+
const endpointChipIds = new Set(this.pins.map((pin) => pin.chipId))
|
|
72
|
+
this.endpointTextObstacles = new Set(
|
|
73
|
+
endpointChipIds.size > 1
|
|
74
|
+
? this.obstacles.filter(
|
|
75
|
+
(r) =>
|
|
76
|
+
r.kind === "text_box" &&
|
|
77
|
+
r.textBox.chipId !== undefined &&
|
|
78
|
+
endpointChipIds.has(r.textBox.chipId),
|
|
79
|
+
)
|
|
80
|
+
: [],
|
|
81
|
+
)
|
|
70
82
|
|
|
71
83
|
// Build initial elbow path
|
|
72
84
|
const [pin1, pin2] = this.pins
|
|
@@ -203,6 +215,38 @@ export class SchematicTraceSingleLineSolver2 extends BaseSolver {
|
|
|
203
215
|
return sum
|
|
204
216
|
}
|
|
205
217
|
|
|
218
|
+
private getPinBandPenalty(path: Point[]): number {
|
|
219
|
+
let penalty = 0
|
|
220
|
+
for (let i = 1; i < path.length - 2; i++) {
|
|
221
|
+
const a = path[i]!
|
|
222
|
+
const b = path[i + 1]!
|
|
223
|
+
if (isHorizontal(a, b) && a.y > this.aabb.minY && a.y < this.aabb.maxY) {
|
|
224
|
+
penalty += 10
|
|
225
|
+
} else if (
|
|
226
|
+
isVertical(a, b) &&
|
|
227
|
+
a.x > this.aabb.minX &&
|
|
228
|
+
a.x < this.aabb.maxX
|
|
229
|
+
) {
|
|
230
|
+
penalty += 10
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
return penalty
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
private pathCost(path: Point[]): number {
|
|
237
|
+
return this.pathLength(path) + this.getPinBandPenalty(path)
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
private isSegmentOutsidePinBand(a: Point, b: Point): boolean {
|
|
241
|
+
if (isHorizontal(a, b)) {
|
|
242
|
+
return a.y <= this.aabb.minY || a.y >= this.aabb.maxY
|
|
243
|
+
}
|
|
244
|
+
if (isVertical(a, b)) {
|
|
245
|
+
return a.x <= this.aabb.minX || a.x >= this.aabb.maxX
|
|
246
|
+
}
|
|
247
|
+
return false
|
|
248
|
+
}
|
|
249
|
+
|
|
206
250
|
override _step() {
|
|
207
251
|
if (this.solvedTracePath) {
|
|
208
252
|
this.solved = true
|
|
@@ -225,6 +269,23 @@ export class SchematicTraceSingleLineSolver2 extends BaseSolver {
|
|
|
225
269
|
if (segIndex === 0 || segIndex === lastSegIndex) {
|
|
226
270
|
return this.textObstacles
|
|
227
271
|
}
|
|
272
|
+
const adjacentEndpointSegIndex =
|
|
273
|
+
segIndex === 1
|
|
274
|
+
? 2
|
|
275
|
+
: segIndex === lastSegIndex - 1
|
|
276
|
+
? lastSegIndex - 2
|
|
277
|
+
: null
|
|
278
|
+
if (
|
|
279
|
+
adjacentEndpointSegIndex !== null &&
|
|
280
|
+
adjacentEndpointSegIndex >= 0 &&
|
|
281
|
+
adjacentEndpointSegIndex < lastSegIndex &&
|
|
282
|
+
this.isSegmentOutsidePinBand(
|
|
283
|
+
path[adjacentEndpointSegIndex]!,
|
|
284
|
+
path[adjacentEndpointSegIndex + 1]!,
|
|
285
|
+
)
|
|
286
|
+
) {
|
|
287
|
+
return this.endpointTextObstacles
|
|
288
|
+
}
|
|
228
289
|
return new Set<ObstacleRect>()
|
|
229
290
|
},
|
|
230
291
|
})
|
|
@@ -246,6 +307,7 @@ export class SchematicTraceSingleLineSolver2 extends BaseSolver {
|
|
|
246
307
|
return
|
|
247
308
|
}
|
|
248
309
|
|
|
310
|
+
const originalSegIndex = collision.segIndex
|
|
249
311
|
let { segIndex, rect } = collision
|
|
250
312
|
|
|
251
313
|
// Never move the first or last segments - move adjacent segment instead
|
|
@@ -301,18 +363,67 @@ export class SchematicTraceSingleLineSolver2 extends BaseSolver {
|
|
|
301
363
|
len: number
|
|
302
364
|
}> = []
|
|
303
365
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
366
|
+
const addShiftedCandidate = (
|
|
367
|
+
candidateSegIndex: number,
|
|
368
|
+
candidateAxis: Axis,
|
|
369
|
+
coord: number,
|
|
370
|
+
) => {
|
|
371
|
+
const newPath = shiftSegmentOrth(
|
|
372
|
+
path,
|
|
373
|
+
candidateSegIndex,
|
|
374
|
+
candidateAxis,
|
|
375
|
+
coord,
|
|
376
|
+
)
|
|
377
|
+
if (!newPath) return
|
|
307
378
|
const key = pathKey(newPath)
|
|
308
|
-
if (this.visited.has(key))
|
|
379
|
+
if (this.visited.has(key)) return
|
|
309
380
|
this.visited.add(key)
|
|
310
381
|
const nextSet = new Set(collisionRects)
|
|
311
382
|
nextSet.add(rect)
|
|
312
|
-
const len = this.
|
|
383
|
+
const len = this.pathCost(newPath)
|
|
313
384
|
newStates.push({ path: newPath, collisionRects: nextSet, len })
|
|
314
385
|
}
|
|
315
386
|
|
|
387
|
+
for (const coord of candidates) {
|
|
388
|
+
addShiftedCandidate(segIndex, axis, coord)
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
const lastSegIndex = path.length - 2
|
|
392
|
+
const adjacentSegmentIndexes =
|
|
393
|
+
originalSegIndex === 1
|
|
394
|
+
? [2]
|
|
395
|
+
: originalSegIndex === lastSegIndex - 1
|
|
396
|
+
? [lastSegIndex - 2]
|
|
397
|
+
: []
|
|
398
|
+
|
|
399
|
+
for (const adjacentSegIndex of adjacentSegmentIndexes) {
|
|
400
|
+
if (adjacentSegIndex < 0 || adjacentSegIndex >= lastSegIndex) continue
|
|
401
|
+
const adjacentAxis = this.axisOfSegment(
|
|
402
|
+
path[adjacentSegIndex]!,
|
|
403
|
+
path[adjacentSegIndex + 1]!,
|
|
404
|
+
)
|
|
405
|
+
if (!adjacentAxis || adjacentAxis === axis) continue
|
|
406
|
+
|
|
407
|
+
const adjacentCandidates = [
|
|
408
|
+
...midBetweenPointAndRect(adjacentAxis, { x: PA.x, y: PA.y }, rect),
|
|
409
|
+
...midBetweenPointAndRect(adjacentAxis, { x: PB.x, y: PB.y }, rect),
|
|
410
|
+
]
|
|
411
|
+
if (collisionRects.size > 0) {
|
|
412
|
+
adjacentCandidates.push(
|
|
413
|
+
...candidateMidsFromSet(
|
|
414
|
+
adjacentAxis,
|
|
415
|
+
rect,
|
|
416
|
+
collisionRects,
|
|
417
|
+
this.aabb,
|
|
418
|
+
),
|
|
419
|
+
)
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
for (const coord of [...new Set(adjacentCandidates)]) {
|
|
423
|
+
addShiftedCandidate(adjacentSegIndex, adjacentAxis, coord)
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
316
427
|
newStates.sort((a, b) => a.len - b.len)
|
|
317
428
|
for (const st of newStates) {
|
|
318
429
|
this.queue.push({ path: st.path, collisionRects: st.collisionRects })
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { mkdir, writeFile } from "node:fs/promises"
|
|
2
2
|
import path from "node:path"
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
getSvgFromGraphicsObject,
|
|
6
|
-
} from "graphics-debug"
|
|
3
|
+
import * as graphicsDebug from "graphics-debug"
|
|
4
|
+
import { getSvgFromGraphicsObject } from "graphics-debug"
|
|
7
5
|
import type { GraphicsObject } from "graphics-debug"
|
|
8
6
|
import { BaseSolver } from "lib/solvers/BaseSolver/BaseSolver"
|
|
9
7
|
import { SchematicTracePipelineSolver } from "lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver"
|
|
@@ -262,6 +260,25 @@ export class PipelineStageDebugRunner {
|
|
|
262
260
|
}
|
|
263
261
|
|
|
264
262
|
private renderGraphicsToPng(graphics: GraphicsObject): Promise<Uint8Array> {
|
|
263
|
+
const getPngBufferFromGraphicsObject = (
|
|
264
|
+
graphicsDebug as unknown as {
|
|
265
|
+
getPngBufferFromGraphicsObject?: (
|
|
266
|
+
graphics: GraphicsObject,
|
|
267
|
+
opts: {
|
|
268
|
+
backgroundColor: string
|
|
269
|
+
pngWidth: number
|
|
270
|
+
pngHeight: number
|
|
271
|
+
},
|
|
272
|
+
) => Promise<Uint8Array>
|
|
273
|
+
}
|
|
274
|
+
).getPngBufferFromGraphicsObject
|
|
275
|
+
|
|
276
|
+
if (!getPngBufferFromGraphicsObject) {
|
|
277
|
+
throw new Error(
|
|
278
|
+
"graphics-debug does not provide getPngBufferFromGraphicsObject; run with --no-png --svg or upgrade graphics-debug",
|
|
279
|
+
)
|
|
280
|
+
}
|
|
281
|
+
|
|
265
282
|
return getPngBufferFromGraphicsObject(graphics, {
|
|
266
283
|
backgroundColor: "white",
|
|
267
284
|
pngWidth: this.pngWidth,
|