@tscircuit/schematic-trace-solver 0.0.98 → 0.0.100
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 -0
- package/dist/index.js +335 -225
- package/lib/solvers/MspConnectionPairSolver/MspConnectionPairSolver.ts +19 -9
- package/lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/SchematicTraceSingleLineSolver2.ts +43 -1
- package/lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/generateEndpointCollisionDetours.ts +84 -0
- package/lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/mid.ts +13 -3
- package/package.json +1 -1
- package/tests/bug-reports/bug-report-20260706T220324Z/__snapshots__/bug-report-20260706T220324Z.snap.svg +18 -18
- package/tests/bug-reports/bug-report-20260707T092615Z/__snapshots__/bug-report-20260707T092615Z.snap.svg +7 -7
- package/tests/bug-reports/bug-report-20260707T134549Z/__snapshots__/bug-report-20260707T134549Z.snap.svg +5 -7
- package/tests/bug-reports/bug-report-20260707T140410Z/__snapshots__/bug-report-20260707T140410Z.snap.svg +6 -12
- package/tests/examples/__snapshots__/example09.snap.svg +9 -13
- package/tests/examples/__snapshots__/example21.snap.svg +30 -32
- package/tests/examples/__snapshots__/example29.snap.svg +13 -19
- package/tests/repros/__snapshots__/repro129-host-custom-symbol-passives.snap.svg +60 -0
- package/tests/repros/__snapshots__/repro47-endpoint-obstacle-detour.snap.svg +65 -0
- package/tests/repros/__snapshots__/repro5-escape-padded-text-obstacles.snap.svg +74 -0
- package/tests/repros/assets/repro129-host-custom-symbol-passives.input.json +94 -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/repro129-host-custom-symbol-passives.test.ts +16 -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/MspConnectionPairSolver/msp-connection-pair-solver-direct-connection-distance.test.ts +46 -0
- package/tests/solvers/SchematicTraceSingleLineSolver2/candidate-mids-from-set.test.ts +39 -0
- package/tests/solvers/SchematicTraceSingleLineSolver2/generate-endpoint-collision-detours.test.ts +38 -0
package/dist/index.js
CHANGED
|
@@ -76,80 +76,39 @@ var BaseSolver = class {
|
|
|
76
76
|
};
|
|
77
77
|
|
|
78
78
|
// lib/solvers/MspConnectionPairSolver/MspConnectionPairSolver.ts
|
|
79
|
-
import "
|
|
79
|
+
import { distance } from "@tscircuit/math-utils";
|
|
80
80
|
|
|
81
|
-
// lib/
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
directConn.netId ? [directConn.netId, ...directConn.pinIds] : directConn.pinIds
|
|
88
|
-
]);
|
|
89
|
-
}
|
|
90
|
-
const netConnMap = new ConnectivityMap(directConnMap.netMap);
|
|
91
|
-
for (const netConn of inputProblem.netConnections) {
|
|
92
|
-
netConnMap.addConnections([[netConn.netId, ...netConn.pinIds]]);
|
|
93
|
-
}
|
|
94
|
-
return { directConnMap, netConnMap };
|
|
81
|
+
// lib/utils/getColorFromString.ts
|
|
82
|
+
var getColorFromString = (string, alpha = 1) => {
|
|
83
|
+
const hash = string.split("").reduce((acc, char) => {
|
|
84
|
+
return acc * 31 + char.charCodeAt(0);
|
|
85
|
+
}, 0);
|
|
86
|
+
return `hsl(${hash % 360}, 100%, 50%, ${alpha})`;
|
|
95
87
|
};
|
|
96
88
|
|
|
97
|
-
// lib/
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
{
|
|
103
|
-
const seen = /* @__PURE__ */ new Set();
|
|
104
|
-
for (const p of pins) {
|
|
105
|
-
if (seen.has(p.pinId)) {
|
|
106
|
-
throw new Error(`Duplicate pinId detected: "${p.pinId}"`);
|
|
107
|
-
}
|
|
108
|
-
seen.add(p.pinId);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
const manhattan = (a, b) => Math.abs(a.x - b.x) + Math.abs(a.y - b.y);
|
|
112
|
-
const inTree = new Array(n).fill(false);
|
|
113
|
-
const bestDist = new Array(n).fill(Number.POSITIVE_INFINITY);
|
|
114
|
-
const parent = new Array(n).fill(-1);
|
|
115
|
-
let startIndex = 0;
|
|
116
|
-
for (let i = 1; i < n; i++) {
|
|
117
|
-
if (pins[i].pinId < pins[startIndex].pinId) startIndex = i;
|
|
89
|
+
// lib/utils/arePinsInDifferentSchematicSections.ts
|
|
90
|
+
var getSectionNameForPin = (sectionByChipId, sectionByPinId, pin) => {
|
|
91
|
+
if (pin.chipId) {
|
|
92
|
+
const chipSection = sectionByChipId.get(pin.chipId);
|
|
93
|
+
if (chipSection) return chipSection;
|
|
118
94
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
best = d;
|
|
130
|
-
bestId = pins[i].pinId;
|
|
131
|
-
u = i;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
inTree[u] = true;
|
|
136
|
-
if (parent[u] !== -1) {
|
|
137
|
-
edges.push([pins[u].pinId, pins[parent[u]].pinId]);
|
|
138
|
-
}
|
|
139
|
-
for (let v = 0; v < n; v++) {
|
|
140
|
-
if (!inTree[v]) {
|
|
141
|
-
const d0 = manhattan(pins[u], pins[v]);
|
|
142
|
-
const isForbidden = opts?.forbidEdge?.(pins[u], pins[v]) ?? false;
|
|
143
|
-
const d = d0 > maxDistance || isForbidden ? Number.POSITIVE_INFINITY : d0;
|
|
144
|
-
if (d < bestDist[v] || d === bestDist[v] && pins[u].pinId < pins[parent[v]]?.pinId) {
|
|
145
|
-
bestDist[v] = d;
|
|
146
|
-
parent[v] = u;
|
|
147
|
-
}
|
|
148
|
-
}
|
|
95
|
+
return sectionByPinId.get(pin.pinId);
|
|
96
|
+
};
|
|
97
|
+
var arePinsInDifferentSchematicSections = (inputProblem, p1, p2) => {
|
|
98
|
+
const sectionByChipId = /* @__PURE__ */ new Map();
|
|
99
|
+
const sectionByPinId = /* @__PURE__ */ new Map();
|
|
100
|
+
for (const chip of inputProblem.chips) {
|
|
101
|
+
if (!chip.sectionId) continue;
|
|
102
|
+
sectionByChipId.set(chip.chipId, chip.sectionId);
|
|
103
|
+
for (const pin of chip.pins) {
|
|
104
|
+
sectionByPinId.set(pin.pinId, chip.sectionId);
|
|
149
105
|
}
|
|
150
106
|
}
|
|
151
|
-
return
|
|
152
|
-
|
|
107
|
+
if (sectionByChipId.size === 0) return false;
|
|
108
|
+
const s1 = getSectionNameForPin(sectionByChipId, sectionByPinId, p1);
|
|
109
|
+
const s2 = getSectionNameForPin(sectionByChipId, sectionByPinId, p2);
|
|
110
|
+
return s1 !== s2;
|
|
111
|
+
};
|
|
153
112
|
|
|
154
113
|
// lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver/getPinDirection.ts
|
|
155
114
|
var getPinDirection = (pin, chip) => {
|
|
@@ -181,6 +140,101 @@ var getPinDirection = (pin, chip) => {
|
|
|
181
140
|
return "x-";
|
|
182
141
|
};
|
|
183
142
|
|
|
143
|
+
// lib/solvers/SchematicTracePipelineSolver/visualizeInputProblem.ts
|
|
144
|
+
var visualizeInputProblem = (inputProblem, opts = {}) => {
|
|
145
|
+
const {
|
|
146
|
+
connectionAlpha = 0.8,
|
|
147
|
+
chipAlpha = 0.8,
|
|
148
|
+
hideRatsNet = inputProblem._hideRatsNet ?? false
|
|
149
|
+
} = opts;
|
|
150
|
+
const graphics = {
|
|
151
|
+
lines: [],
|
|
152
|
+
points: [],
|
|
153
|
+
rects: []
|
|
154
|
+
};
|
|
155
|
+
const pinIdMap = /* @__PURE__ */ new Map();
|
|
156
|
+
for (const chip of inputProblem.chips) {
|
|
157
|
+
for (const pin of chip.pins) {
|
|
158
|
+
pinIdMap.set(pin.pinId, pin);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
for (const chip of inputProblem.chips) {
|
|
162
|
+
graphics.rects.push({
|
|
163
|
+
label: chip.chipId,
|
|
164
|
+
center: chip.center,
|
|
165
|
+
width: chip.width,
|
|
166
|
+
height: chip.height,
|
|
167
|
+
fill: getColorFromString(chip.chipId, chipAlpha)
|
|
168
|
+
});
|
|
169
|
+
for (const pin of chip.pins) {
|
|
170
|
+
graphics.points.push({
|
|
171
|
+
label: `${pin.pinId}
|
|
172
|
+
${pin._facingDirection ?? getPinDirection(pin, chip)}`,
|
|
173
|
+
x: pin.x,
|
|
174
|
+
y: pin.y,
|
|
175
|
+
color: getColorFromString(pin.pinId, 0.8)
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
for (const textBox of inputProblem.textBoxes ?? []) {
|
|
180
|
+
graphics.rects.push({
|
|
181
|
+
label: textBox.text ?? "schematic_text",
|
|
182
|
+
center: textBox.center,
|
|
183
|
+
width: textBox.width,
|
|
184
|
+
height: textBox.height,
|
|
185
|
+
fill: "rgba(160, 0, 220, 0.14)",
|
|
186
|
+
strokeColor: "rgba(160, 0, 220, 0.9)"
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
if (!hideRatsNet) {
|
|
190
|
+
for (const directConn of inputProblem.directConnections) {
|
|
191
|
+
const [pinId1, pinId2] = directConn.pinIds;
|
|
192
|
+
const pin1 = pinIdMap.get(pinId1);
|
|
193
|
+
const pin2 = pinIdMap.get(pinId2);
|
|
194
|
+
if (arePinsInDifferentSchematicSections(inputProblem, pin1, pin2)) {
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
graphics.lines.push({
|
|
198
|
+
points: [
|
|
199
|
+
{
|
|
200
|
+
x: pin1.x,
|
|
201
|
+
y: pin1.y
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
x: pin2.x,
|
|
205
|
+
y: pin2.y
|
|
206
|
+
}
|
|
207
|
+
],
|
|
208
|
+
strokeColor: getColorFromString(
|
|
209
|
+
directConn.netId ?? `${pinId1}-${pinId2}`,
|
|
210
|
+
connectionAlpha
|
|
211
|
+
)
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
for (const netConn of inputProblem.netConnections) {
|
|
215
|
+
const pins = netConn.pinIds.map((pinId) => pinIdMap.get(pinId));
|
|
216
|
+
for (let i = 0; i < pins.length - 1; i++) {
|
|
217
|
+
for (let j = i + 1; j < pins.length; j++) {
|
|
218
|
+
const pin1 = pins[i];
|
|
219
|
+
const pin2 = pins[j];
|
|
220
|
+
if (arePinsInDifferentSchematicSections(inputProblem, pin1, pin2)) {
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
graphics.lines.push({
|
|
224
|
+
points: [
|
|
225
|
+
{ x: pin1.x, y: pin1.y },
|
|
226
|
+
{ x: pin2.x, y: pin2.y }
|
|
227
|
+
],
|
|
228
|
+
strokeColor: getColorFromString(netConn.netId, connectionAlpha),
|
|
229
|
+
strokeDash: "4 2"
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
return graphics;
|
|
236
|
+
};
|
|
237
|
+
|
|
184
238
|
// lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver/getRestrictedCenterLines.ts
|
|
185
239
|
var getRestrictedCenterLines = (params) => {
|
|
186
240
|
const { pins, inputProblem, pinIdMap, chipMap } = params;
|
|
@@ -293,134 +347,81 @@ var doesPairCrossRestrictedCenterLines = (params) => {
|
|
|
293
347
|
return hvCrosses && vhCrosses;
|
|
294
348
|
};
|
|
295
349
|
|
|
296
|
-
// lib/
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
// lib/utils/arePinsInDifferentSchematicSections.ts
|
|
305
|
-
var getSectionNameForPin = (sectionByChipId, sectionByPinId, pin) => {
|
|
306
|
-
if (pin.chipId) {
|
|
307
|
-
const chipSection = sectionByChipId.get(pin.chipId);
|
|
308
|
-
if (chipSection) return chipSection;
|
|
350
|
+
// lib/solvers/MspConnectionPairSolver/getConnectivityMapFromInputProblem.ts
|
|
351
|
+
import { ConnectivityMap } from "connectivity-map";
|
|
352
|
+
var getConnectivityMapsFromInputProblem = (inputProblem) => {
|
|
353
|
+
const directConnMap = new ConnectivityMap({});
|
|
354
|
+
for (const directConn of inputProblem.directConnections) {
|
|
355
|
+
directConnMap.addConnections([
|
|
356
|
+
directConn.netId ? [directConn.netId, ...directConn.pinIds] : directConn.pinIds
|
|
357
|
+
]);
|
|
309
358
|
}
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
const sectionByChipId = /* @__PURE__ */ new Map();
|
|
314
|
-
const sectionByPinId = /* @__PURE__ */ new Map();
|
|
315
|
-
for (const chip of inputProblem.chips) {
|
|
316
|
-
if (!chip.sectionId) continue;
|
|
317
|
-
sectionByChipId.set(chip.chipId, chip.sectionId);
|
|
318
|
-
for (const pin of chip.pins) {
|
|
319
|
-
sectionByPinId.set(pin.pinId, chip.sectionId);
|
|
320
|
-
}
|
|
359
|
+
const netConnMap = new ConnectivityMap(directConnMap.netMap);
|
|
360
|
+
for (const netConn of inputProblem.netConnections) {
|
|
361
|
+
netConnMap.addConnections([[netConn.netId, ...netConn.pinIds]]);
|
|
321
362
|
}
|
|
322
|
-
|
|
323
|
-
const s1 = getSectionNameForPin(sectionByChipId, sectionByPinId, p1);
|
|
324
|
-
const s2 = getSectionNameForPin(sectionByChipId, sectionByPinId, p2);
|
|
325
|
-
return s1 !== s2;
|
|
363
|
+
return { directConnMap, netConnMap };
|
|
326
364
|
};
|
|
327
365
|
|
|
328
|
-
// lib/solvers/
|
|
329
|
-
|
|
330
|
-
const
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
const pinIdMap = /* @__PURE__ */ new Map();
|
|
341
|
-
for (const chip of inputProblem.chips) {
|
|
342
|
-
for (const pin of chip.pins) {
|
|
343
|
-
pinIdMap.set(pin.pinId, pin);
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
for (const chip of inputProblem.chips) {
|
|
347
|
-
graphics.rects.push({
|
|
348
|
-
label: chip.chipId,
|
|
349
|
-
center: chip.center,
|
|
350
|
-
width: chip.width,
|
|
351
|
-
height: chip.height,
|
|
352
|
-
fill: getColorFromString(chip.chipId, chipAlpha)
|
|
353
|
-
});
|
|
354
|
-
for (const pin of chip.pins) {
|
|
355
|
-
graphics.points.push({
|
|
356
|
-
label: `${pin.pinId}
|
|
357
|
-
${pin._facingDirection ?? getPinDirection(pin, chip)}`,
|
|
358
|
-
x: pin.x,
|
|
359
|
-
y: pin.y,
|
|
360
|
-
color: getColorFromString(pin.pinId, 0.8)
|
|
361
|
-
});
|
|
366
|
+
// lib/solvers/MspConnectionPairSolver/getMspConnectionPairsFromPins.ts
|
|
367
|
+
function getOrthogonalMinimumSpanningTree(pins, opts = {}) {
|
|
368
|
+
const n = pins.length;
|
|
369
|
+
const maxDistance = opts?.maxDistance ?? Number.POSITIVE_INFINITY;
|
|
370
|
+
if (n <= 1) return [];
|
|
371
|
+
{
|
|
372
|
+
const seen = /* @__PURE__ */ new Set();
|
|
373
|
+
for (const p of pins) {
|
|
374
|
+
if (seen.has(p.pinId)) {
|
|
375
|
+
throw new Error(`Duplicate pinId detected: "${p.pinId}"`);
|
|
376
|
+
}
|
|
377
|
+
seen.add(p.pinId);
|
|
362
378
|
}
|
|
363
379
|
}
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
strokeColor: "rgba(160, 0, 220, 0.9)"
|
|
372
|
-
});
|
|
380
|
+
const manhattan = (a, b) => Math.abs(a.x - b.x) + Math.abs(a.y - b.y);
|
|
381
|
+
const inTree = new Array(n).fill(false);
|
|
382
|
+
const bestDist = new Array(n).fill(Number.POSITIVE_INFINITY);
|
|
383
|
+
const parent = new Array(n).fill(-1);
|
|
384
|
+
let startIndex = 0;
|
|
385
|
+
for (let i = 1; i < n; i++) {
|
|
386
|
+
if (pins[i].pinId < pins[startIndex].pinId) startIndex = i;
|
|
373
387
|
}
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
388
|
+
bestDist[startIndex] = 0;
|
|
389
|
+
const edges = [];
|
|
390
|
+
for (let iter = 0; iter < n; iter++) {
|
|
391
|
+
let u = -1;
|
|
392
|
+
let best = Number.POSITIVE_INFINITY;
|
|
393
|
+
let bestId = "";
|
|
394
|
+
for (let i = 0; i < n; i++) {
|
|
395
|
+
if (!inTree[i]) {
|
|
396
|
+
const d = bestDist[i];
|
|
397
|
+
if (d < best || d === best && (bestId === "" || pins[i].pinId < bestId)) {
|
|
398
|
+
best = d;
|
|
399
|
+
bestId = pins[i].pinId;
|
|
400
|
+
u = i;
|
|
401
|
+
}
|
|
381
402
|
}
|
|
382
|
-
graphics.lines.push({
|
|
383
|
-
points: [
|
|
384
|
-
{
|
|
385
|
-
x: pin1.x,
|
|
386
|
-
y: pin1.y
|
|
387
|
-
},
|
|
388
|
-
{
|
|
389
|
-
x: pin2.x,
|
|
390
|
-
y: pin2.y
|
|
391
|
-
}
|
|
392
|
-
],
|
|
393
|
-
strokeColor: getColorFromString(
|
|
394
|
-
directConn.netId ?? `${pinId1}-${pinId2}`,
|
|
395
|
-
connectionAlpha
|
|
396
|
-
)
|
|
397
|
-
});
|
|
398
403
|
}
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
{ x: pin2.x, y: pin2.y }
|
|
412
|
-
],
|
|
413
|
-
strokeColor: getColorFromString(netConn.netId, connectionAlpha),
|
|
414
|
-
strokeDash: "4 2"
|
|
415
|
-
});
|
|
404
|
+
inTree[u] = true;
|
|
405
|
+
if (parent[u] !== -1) {
|
|
406
|
+
edges.push([pins[u].pinId, pins[parent[u]].pinId]);
|
|
407
|
+
}
|
|
408
|
+
for (let v = 0; v < n; v++) {
|
|
409
|
+
if (!inTree[v]) {
|
|
410
|
+
const d0 = manhattan(pins[u], pins[v]);
|
|
411
|
+
const isForbidden = opts?.forbidEdge?.(pins[u], pins[v]) ?? false;
|
|
412
|
+
const d = d0 > maxDistance || isForbidden ? Number.POSITIVE_INFINITY : d0;
|
|
413
|
+
if (d < bestDist[v] || d === bestDist[v] && pins[u].pinId < pins[parent[v]]?.pinId) {
|
|
414
|
+
bestDist[v] = d;
|
|
415
|
+
parent[v] = u;
|
|
416
416
|
}
|
|
417
417
|
}
|
|
418
418
|
}
|
|
419
419
|
}
|
|
420
|
-
return
|
|
421
|
-
}
|
|
420
|
+
return edges;
|
|
421
|
+
}
|
|
422
422
|
|
|
423
423
|
// lib/solvers/MspConnectionPairSolver/MspConnectionPairSolver.ts
|
|
424
|
+
var getPinPairKey = (pinIds) => [...pinIds].sort().join("::");
|
|
424
425
|
var MspConnectionPairSolver = class extends BaseSolver {
|
|
425
426
|
inputProblem;
|
|
426
427
|
mspConnectionPairs = [];
|
|
@@ -431,6 +432,7 @@ var MspConnectionPairSolver = class extends BaseSolver {
|
|
|
431
432
|
maxMspPairDistance;
|
|
432
433
|
pinMap;
|
|
433
434
|
userNetIdByPinId;
|
|
435
|
+
directConnectionPinPairKeys;
|
|
434
436
|
constructor({ inputProblem }) {
|
|
435
437
|
super();
|
|
436
438
|
this.inputProblem = inputProblem;
|
|
@@ -449,7 +451,9 @@ var MspConnectionPairSolver = class extends BaseSolver {
|
|
|
449
451
|
this.chipMap[chip.chipId] = chip;
|
|
450
452
|
}
|
|
451
453
|
this.userNetIdByPinId = {};
|
|
454
|
+
this.directConnectionPinPairKeys = /* @__PURE__ */ new Set();
|
|
452
455
|
for (const dc of inputProblem.directConnections) {
|
|
456
|
+
this.directConnectionPinPairKeys.add(getPinPairKey(dc.pinIds));
|
|
453
457
|
if (dc.netId) {
|
|
454
458
|
const [a, b] = dc.pinIds;
|
|
455
459
|
this.userNetIdByPinId[a] = dc.netId;
|
|
@@ -483,8 +487,9 @@ var MspConnectionPairSolver = class extends BaseSolver {
|
|
|
483
487
|
const [pin1, pin2] = directlyConnectedPins;
|
|
484
488
|
const p1 = this.pinMap[pin1];
|
|
485
489
|
const p2 = this.pinMap[pin2];
|
|
486
|
-
const
|
|
487
|
-
|
|
490
|
+
const pinPairKey = getPinPairKey([pin1, pin2]);
|
|
491
|
+
const pairDistance = this.directConnectionPinPairKeys.has(pinPairKey) ? distance(p1, p2) : Math.abs(p1.x - p2.x) + Math.abs(p1.y - p2.y);
|
|
492
|
+
if (pairDistance > this.maxMspPairDistance) {
|
|
488
493
|
return;
|
|
489
494
|
}
|
|
490
495
|
if (arePinsInDifferentSchematicSections(this.inputProblem, p1, p2)) {
|
|
@@ -796,6 +801,7 @@ var isPathCollidingWithObstacles = (path, obstacles) => {
|
|
|
796
801
|
|
|
797
802
|
// lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/mid.ts
|
|
798
803
|
var EPS2 = 1e-9;
|
|
804
|
+
var OBSTACLE_CLEARANCE = 0.2;
|
|
799
805
|
var aabbFromPoints = (a, b) => ({
|
|
800
806
|
minX: Math.min(a.x, b.x),
|
|
801
807
|
maxX: Math.max(a.x, b.x),
|
|
@@ -810,7 +816,7 @@ var midBetweenPointAndRect = (axis, p, r, eps = EPS2) => {
|
|
|
810
816
|
if (p.x > r.maxX + eps) {
|
|
811
817
|
return [(p.x + r.maxX) / 2];
|
|
812
818
|
}
|
|
813
|
-
return [r.minX -
|
|
819
|
+
return [r.minX - OBSTACLE_CLEARANCE, r.maxX + OBSTACLE_CLEARANCE];
|
|
814
820
|
} else {
|
|
815
821
|
if (p.y < r.minY - eps) {
|
|
816
822
|
return [(p.y + r.minY) / 2];
|
|
@@ -818,10 +824,11 @@ var midBetweenPointAndRect = (axis, p, r, eps = EPS2) => {
|
|
|
818
824
|
if (p.y > r.maxY + eps) {
|
|
819
825
|
return [(p.y + r.maxY) / 2];
|
|
820
826
|
}
|
|
821
|
-
return [r.minY -
|
|
827
|
+
return [r.minY - OBSTACLE_CLEARANCE, r.maxY + OBSTACLE_CLEARANCE];
|
|
822
828
|
}
|
|
823
829
|
};
|
|
824
|
-
var candidateMidsFromSet = (axis, colliding, collisionRects, aabb,
|
|
830
|
+
var candidateMidsFromSet = (axis, colliding, collisionRects, aabb, opts = {}) => {
|
|
831
|
+
const { allowOpenSideCandidates = false, eps = EPS2 } = opts;
|
|
825
832
|
const setRects = [...collisionRects];
|
|
826
833
|
if (axis === "x") {
|
|
827
834
|
const leftBoundaries = [aabb.minX, ...setRects.map((r) => r.maxX)].filter(
|
|
@@ -835,9 +842,13 @@ var candidateMidsFromSet = (axis, colliding, collisionRects, aabb, eps = EPS2) =
|
|
|
835
842
|
const out = [];
|
|
836
843
|
if (leftNeighbor !== void 0) {
|
|
837
844
|
out.push((leftNeighbor + colliding.minX) / 2);
|
|
845
|
+
} else if (allowOpenSideCandidates) {
|
|
846
|
+
out.push(colliding.minX - OBSTACLE_CLEARANCE);
|
|
838
847
|
}
|
|
839
848
|
if (rightNeighbor !== void 0) {
|
|
840
849
|
out.push((colliding.maxX + rightNeighbor) / 2);
|
|
850
|
+
} else if (allowOpenSideCandidates) {
|
|
851
|
+
out.push(colliding.maxX + OBSTACLE_CLEARANCE);
|
|
841
852
|
}
|
|
842
853
|
return out;
|
|
843
854
|
} else {
|
|
@@ -852,14 +863,80 @@ var candidateMidsFromSet = (axis, colliding, collisionRects, aabb, eps = EPS2) =
|
|
|
852
863
|
const out = [];
|
|
853
864
|
if (bottomNeighbor !== void 0) {
|
|
854
865
|
out.push((bottomNeighbor + colliding.minY) / 2);
|
|
866
|
+
} else if (allowOpenSideCandidates) {
|
|
867
|
+
out.push(colliding.minY - OBSTACLE_CLEARANCE);
|
|
855
868
|
}
|
|
856
869
|
if (topNeighbor !== void 0) {
|
|
857
870
|
out.push((colliding.maxY + topNeighbor) / 2);
|
|
871
|
+
} else if (allowOpenSideCandidates) {
|
|
872
|
+
out.push(colliding.maxY + OBSTACLE_CLEARANCE);
|
|
858
873
|
}
|
|
859
874
|
return out;
|
|
860
875
|
}
|
|
861
876
|
};
|
|
862
877
|
|
|
878
|
+
// lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/generateEndpointCollisionDetours.ts
|
|
879
|
+
var getSegmentAxis = (start, end) => {
|
|
880
|
+
if (isVertical(start, end)) return "x";
|
|
881
|
+
if (isHorizontal(start, end)) return "y";
|
|
882
|
+
return null;
|
|
883
|
+
};
|
|
884
|
+
var hasOnlyNonzeroOrthogonalSegments = (path) => path.every((point, index) => {
|
|
885
|
+
const nextPoint = path[index + 1];
|
|
886
|
+
if (!nextPoint) return true;
|
|
887
|
+
if (!isHorizontal(point, nextPoint) && !isVertical(point, nextPoint)) {
|
|
888
|
+
return false;
|
|
889
|
+
}
|
|
890
|
+
return Math.abs(point.x - nextPoint.x) + Math.abs(point.y - nextPoint.y) > 0;
|
|
891
|
+
});
|
|
892
|
+
var generateEndpointCollisionDetours = ({
|
|
893
|
+
path,
|
|
894
|
+
collidingSegmentIndex,
|
|
895
|
+
obstacle
|
|
896
|
+
}) => {
|
|
897
|
+
if (path.length !== 3) return [];
|
|
898
|
+
const lastSegmentIndex = path.length - 2;
|
|
899
|
+
if (collidingSegmentIndex !== 0 && collidingSegmentIndex !== lastSegmentIndex) {
|
|
900
|
+
return [];
|
|
901
|
+
}
|
|
902
|
+
const shouldReverse = collidingSegmentIndex === lastSegmentIndex;
|
|
903
|
+
const orderedPath = shouldReverse ? [...path].reverse() : path;
|
|
904
|
+
const [start, corner, end] = orderedPath;
|
|
905
|
+
const firstSegmentAxis = getSegmentAxis(start, corner);
|
|
906
|
+
const secondSegmentAxis = getSegmentAxis(corner, end);
|
|
907
|
+
if (!firstSegmentAxis || !secondSegmentAxis) return [];
|
|
908
|
+
if (firstSegmentAxis === secondSegmentAxis) return [];
|
|
909
|
+
const escapeCoordinates = [
|
|
910
|
+
...midBetweenPointAndRect(secondSegmentAxis, start, obstacle),
|
|
911
|
+
...midBetweenPointAndRect(secondSegmentAxis, end, obstacle)
|
|
912
|
+
];
|
|
913
|
+
const detourCoordinates = [
|
|
914
|
+
...midBetweenPointAndRect(firstSegmentAxis, start, obstacle),
|
|
915
|
+
...midBetweenPointAndRect(firstSegmentAxis, end, obstacle)
|
|
916
|
+
];
|
|
917
|
+
const detours = [];
|
|
918
|
+
for (const escapeCoordinate of [...new Set(escapeCoordinates)]) {
|
|
919
|
+
for (const detourCoordinate of [...new Set(detourCoordinates)]) {
|
|
920
|
+
const orderedDetour = firstSegmentAxis === "y" ? [
|
|
921
|
+
start,
|
|
922
|
+
{ x: escapeCoordinate, y: start.y },
|
|
923
|
+
{ x: escapeCoordinate, y: detourCoordinate },
|
|
924
|
+
{ x: end.x, y: detourCoordinate },
|
|
925
|
+
end
|
|
926
|
+
] : [
|
|
927
|
+
start,
|
|
928
|
+
{ x: start.x, y: escapeCoordinate },
|
|
929
|
+
{ x: detourCoordinate, y: escapeCoordinate },
|
|
930
|
+
{ x: detourCoordinate, y: end.y },
|
|
931
|
+
end
|
|
932
|
+
];
|
|
933
|
+
const detour = shouldReverse ? orderedDetour.reverse() : orderedDetour;
|
|
934
|
+
if (hasOnlyNonzeroOrthogonalSegments(detour)) detours.push(detour);
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
return detours;
|
|
938
|
+
};
|
|
939
|
+
|
|
863
940
|
// lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/pathOps.ts
|
|
864
941
|
var EPS3 = 1e-9;
|
|
865
942
|
var shiftSegmentOrth = (pts, segIndex, axis, newCoord, eps = EPS3) => {
|
|
@@ -1210,6 +1287,29 @@ var SchematicTraceSingleLineSolver2 = class extends BaseSolver {
|
|
|
1210
1287
|
let { segIndex, rect } = collision;
|
|
1211
1288
|
const isFirstSegment = segIndex === 0;
|
|
1212
1289
|
const isLastSegment = segIndex === path.length - 2;
|
|
1290
|
+
if (path.length === 3 && (isFirstSegment || isLastSegment)) {
|
|
1291
|
+
const detours = generateEndpointCollisionDetours({
|
|
1292
|
+
path,
|
|
1293
|
+
collidingSegmentIndex: segIndex,
|
|
1294
|
+
obstacle: rect
|
|
1295
|
+
}).filter((detour) => {
|
|
1296
|
+
const key = pathKey(detour);
|
|
1297
|
+
if (this.visited.has(key)) return false;
|
|
1298
|
+
this.visited.add(key);
|
|
1299
|
+
return true;
|
|
1300
|
+
}).sort(
|
|
1301
|
+
(a2, b2) => this.pathLength(a2) - this.pathLength(b2) || this.getPinBandPenalty(a2) - this.getPinBandPenalty(b2)
|
|
1302
|
+
);
|
|
1303
|
+
for (const detour of detours) {
|
|
1304
|
+
const nextCollisionRects = new Set(collisionRects);
|
|
1305
|
+
nextCollisionRects.add(rect);
|
|
1306
|
+
this.queue.push({
|
|
1307
|
+
path: detour,
|
|
1308
|
+
collisionRects: nextCollisionRects
|
|
1309
|
+
});
|
|
1310
|
+
}
|
|
1311
|
+
return;
|
|
1312
|
+
}
|
|
1213
1313
|
if (isFirstSegment) {
|
|
1214
1314
|
if (path.length < 3) {
|
|
1215
1315
|
return;
|
|
@@ -1228,6 +1328,9 @@ var SchematicTraceSingleLineSolver2 = class extends BaseSolver {
|
|
|
1228
1328
|
return;
|
|
1229
1329
|
}
|
|
1230
1330
|
const candidates = [];
|
|
1331
|
+
const candidateMidOptions = {
|
|
1332
|
+
allowOpenSideCandidates: this.connectionPair !== void 0
|
|
1333
|
+
};
|
|
1231
1334
|
if (collisionRects.size === 0) {
|
|
1232
1335
|
const m1 = midBetweenPointAndRect(axis, { x: PA.x, y: PA.y }, rect);
|
|
1233
1336
|
const m2 = midBetweenPointAndRect(axis, { x: PB.x, y: PB.y }, rect);
|
|
@@ -1235,7 +1338,13 @@ var SchematicTraceSingleLineSolver2 = class extends BaseSolver {
|
|
|
1235
1338
|
const uniqueCandidates = [...new Set(allCandidates)];
|
|
1236
1339
|
candidates.push(...uniqueCandidates);
|
|
1237
1340
|
} else {
|
|
1238
|
-
const mids = candidateMidsFromSet(
|
|
1341
|
+
const mids = candidateMidsFromSet(
|
|
1342
|
+
axis,
|
|
1343
|
+
rect,
|
|
1344
|
+
collisionRects,
|
|
1345
|
+
this.aabb,
|
|
1346
|
+
candidateMidOptions
|
|
1347
|
+
);
|
|
1239
1348
|
candidates.push(...mids);
|
|
1240
1349
|
}
|
|
1241
1350
|
const newStates = [];
|
|
@@ -1281,7 +1390,8 @@ var SchematicTraceSingleLineSolver2 = class extends BaseSolver {
|
|
|
1281
1390
|
adjacentAxis,
|
|
1282
1391
|
rect,
|
|
1283
1392
|
collisionRects,
|
|
1284
|
-
this.aabb
|
|
1393
|
+
this.aabb,
|
|
1394
|
+
candidateMidOptions
|
|
1285
1395
|
)
|
|
1286
1396
|
);
|
|
1287
1397
|
}
|
|
@@ -2961,7 +3071,7 @@ var mergeLabelGroup = (group, groupKey) => {
|
|
|
2961
3071
|
};
|
|
2962
3072
|
|
|
2963
3073
|
// lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/LabelMergingSolver/filterLabelsAtTraceEdges.ts
|
|
2964
|
-
import { distance } from "@tscircuit/math-utils";
|
|
3074
|
+
import { distance as distance2 } from "@tscircuit/math-utils";
|
|
2965
3075
|
var filterLabelsAtTraceEdges = ({
|
|
2966
3076
|
labels,
|
|
2967
3077
|
traces,
|
|
@@ -2994,8 +3104,8 @@ var filterLabelsAtTraceEdges = ({
|
|
|
2994
3104
|
if (trace.tracePath.length === 0) continue;
|
|
2995
3105
|
const startPoint = trace.tracePath[0];
|
|
2996
3106
|
const endPoint = trace.tracePath[trace.tracePath.length - 1];
|
|
2997
|
-
const startDist =
|
|
2998
|
-
const endDist =
|
|
3107
|
+
const startDist = distance2(label.center, startPoint);
|
|
3108
|
+
const endDist = distance2(label.center, endPoint);
|
|
2999
3109
|
if (startDist <= distanceThreshold || endDist <= distanceThreshold) {
|
|
3000
3110
|
isNearTraceEdge = true;
|
|
3001
3111
|
break;
|
|
@@ -4077,7 +4187,7 @@ function doesTraceOverlapWithExistingTraces(newTracePath, existingTraces) {
|
|
|
4077
4187
|
|
|
4078
4188
|
// lib/solvers/LongDistancePairSolver/LongDistancePairSolver.ts
|
|
4079
4189
|
var NEAREST_NEIGHBOR_COUNT = 3;
|
|
4080
|
-
var
|
|
4190
|
+
var distance3 = (p1, p2) => {
|
|
4081
4191
|
return Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2));
|
|
4082
4192
|
};
|
|
4083
4193
|
var LongDistancePairSolver = class extends BaseSolver {
|
|
@@ -4118,7 +4228,7 @@ var LongDistancePairSolver = class extends BaseSolver {
|
|
|
4118
4228
|
return [
|
|
4119
4229
|
{
|
|
4120
4230
|
pin: targetPin,
|
|
4121
|
-
distance:
|
|
4231
|
+
distance: distance3(sourcePin, targetPin)
|
|
4122
4232
|
}
|
|
4123
4233
|
];
|
|
4124
4234
|
}).sort((a, b) => a.distance - b.distance).slice(0, NEAREST_NEIGHBOR_COUNT);
|
|
@@ -4932,10 +5042,10 @@ var projectPointToPath = (point, path) => {
|
|
|
4932
5042
|
let bestDistance = Number.POSITIVE_INFINITY;
|
|
4933
5043
|
for (let i = 0; i < path.length - 1; i++) {
|
|
4934
5044
|
const projectedPoint = projectPointToSegment(point, path[i], path[i + 1]);
|
|
4935
|
-
const
|
|
4936
|
-
if (
|
|
5045
|
+
const distance4 = getDistance2(point, projectedPoint);
|
|
5046
|
+
if (distance4 < bestDistance) {
|
|
4937
5047
|
bestPoint = projectedPoint;
|
|
4938
|
-
bestDistance =
|
|
5048
|
+
bestDistance = distance4;
|
|
4939
5049
|
}
|
|
4940
5050
|
}
|
|
4941
5051
|
return bestPoint;
|
|
@@ -6565,11 +6675,11 @@ var getLabelHugDistance = (tracePath, obstacleLabel) => {
|
|
|
6565
6675
|
obstacleLabel.width,
|
|
6566
6676
|
obstacleLabel.height
|
|
6567
6677
|
);
|
|
6568
|
-
let
|
|
6678
|
+
let distance4 = 0;
|
|
6569
6679
|
for (const point of tracePath) {
|
|
6570
|
-
|
|
6680
|
+
distance4 += getPointDistanceFromRect(point, bounds);
|
|
6571
6681
|
}
|
|
6572
|
-
return
|
|
6682
|
+
return distance4;
|
|
6573
6683
|
};
|
|
6574
6684
|
var getPointDistanceFromRect = (point, rect) => {
|
|
6575
6685
|
const dx = Math.max(rect.minX - point.x, 0, point.x - rect.maxX);
|
|
@@ -6846,16 +6956,16 @@ var Example28Solver = class extends BaseSolver {
|
|
|
6846
6956
|
const outward = dir(label.orientation);
|
|
6847
6957
|
if (outward.x === 0 && outward.y === 0) return null;
|
|
6848
6958
|
for (let step = 1; step <= LABEL_MAX_OUTWARD_STEPS; step++) {
|
|
6849
|
-
const
|
|
6959
|
+
const distance4 = step * LABEL_OUTWARD_STEP;
|
|
6850
6960
|
const candidate = {
|
|
6851
6961
|
...label,
|
|
6852
6962
|
anchorPoint: {
|
|
6853
|
-
x: label.anchorPoint.x + outward.x *
|
|
6854
|
-
y: label.anchorPoint.y + outward.y *
|
|
6963
|
+
x: label.anchorPoint.x + outward.x * distance4,
|
|
6964
|
+
y: label.anchorPoint.y + outward.y * distance4
|
|
6855
6965
|
},
|
|
6856
6966
|
center: {
|
|
6857
|
-
x: label.center.x + outward.x *
|
|
6858
|
-
y: label.center.y + outward.y *
|
|
6967
|
+
x: label.center.x + outward.x * distance4,
|
|
6968
|
+
y: label.center.y + outward.y * distance4
|
|
6859
6969
|
}
|
|
6860
6970
|
};
|
|
6861
6971
|
const candidateWithClearance = {
|
|
@@ -7393,10 +7503,10 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
7393
7503
|
outwardDistance,
|
|
7394
7504
|
phase = "shift"
|
|
7395
7505
|
} = params;
|
|
7396
|
-
for (let
|
|
7506
|
+
for (let distance4 = LABEL_SEARCH_STEP; distance4 <= maxSearchDistance + EPS9; distance4 += LABEL_SEARCH_STEP) {
|
|
7397
7507
|
const anchorPoint = {
|
|
7398
|
-
x: baseAnchor.x + direction.x *
|
|
7399
|
-
y: baseAnchor.y + direction.y *
|
|
7508
|
+
x: baseAnchor.x + direction.x * distance4,
|
|
7509
|
+
y: baseAnchor.y + direction.y * distance4
|
|
7400
7510
|
};
|
|
7401
7511
|
const candidate = this.createCandidate(label, anchorPoint, orientation);
|
|
7402
7512
|
const result = this.evaluateCandidate(
|
|
@@ -7404,7 +7514,7 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
7404
7514
|
label,
|
|
7405
7515
|
labelIndex,
|
|
7406
7516
|
phase,
|
|
7407
|
-
|
|
7517
|
+
distance4,
|
|
7408
7518
|
outwardDistance
|
|
7409
7519
|
);
|
|
7410
7520
|
this.currentCandidateResults.push(result);
|
|
@@ -7416,11 +7526,11 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
7416
7526
|
}
|
|
7417
7527
|
return null;
|
|
7418
7528
|
}
|
|
7419
|
-
evaluateCandidate(candidate, label, labelIndex, phase,
|
|
7529
|
+
evaluateCandidate(candidate, label, labelIndex, phase, distance4, outwardDistance) {
|
|
7420
7530
|
return {
|
|
7421
7531
|
...candidate,
|
|
7422
7532
|
phase,
|
|
7423
|
-
distance:
|
|
7533
|
+
distance: distance4,
|
|
7424
7534
|
outwardDistance,
|
|
7425
7535
|
selected: false,
|
|
7426
7536
|
status: this.getCandidateStatus({
|
|
@@ -7758,10 +7868,10 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
7758
7868
|
if (point.x < bounds.minX - EPS9 || point.x > bounds.maxX + EPS9 || point.y < bounds.minY - EPS9 || point.y > bounds.maxY + EPS9) {
|
|
7759
7869
|
continue;
|
|
7760
7870
|
}
|
|
7761
|
-
for (const [side,
|
|
7762
|
-
if (
|
|
7871
|
+
for (const [side, distance4] of getSideDistances(point, bounds)) {
|
|
7872
|
+
if (distance4 < nearestDistance) {
|
|
7763
7873
|
nearestSide = side;
|
|
7764
|
-
nearestDistance =
|
|
7874
|
+
nearestDistance = distance4;
|
|
7765
7875
|
}
|
|
7766
7876
|
}
|
|
7767
7877
|
}
|
|
@@ -7790,10 +7900,10 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
7790
7900
|
let nearestSide = null;
|
|
7791
7901
|
let nearestDistance = Number.POSITIVE_INFINITY;
|
|
7792
7902
|
for (const chip of this.chipObstacleSpatialIndex.chips) {
|
|
7793
|
-
for (const [side,
|
|
7794
|
-
if (
|
|
7903
|
+
for (const [side, distance4] of getSideDistances(point, chip.bounds)) {
|
|
7904
|
+
if (distance4 < nearestDistance) {
|
|
7795
7905
|
nearestSide = side;
|
|
7796
|
-
nearestDistance =
|
|
7906
|
+
nearestDistance = distance4;
|
|
7797
7907
|
}
|
|
7798
7908
|
}
|
|
7799
7909
|
}
|
|
@@ -8194,17 +8304,17 @@ var getTraceLength = (trace) => {
|
|
|
8194
8304
|
}
|
|
8195
8305
|
return length;
|
|
8196
8306
|
};
|
|
8197
|
-
var getPointAtTraceDistance = (trace,
|
|
8307
|
+
var getPointAtTraceDistance = (trace, distance4) => {
|
|
8198
8308
|
let pathDistance = 0;
|
|
8199
8309
|
for (let i = 0; i < trace.tracePath.length - 1; i++) {
|
|
8200
8310
|
const start = trace.tracePath[i];
|
|
8201
8311
|
const end = trace.tracePath[i + 1];
|
|
8202
8312
|
const segmentLength = getManhattanDistance(start, end);
|
|
8203
8313
|
const nextDistance = pathDistance + segmentLength;
|
|
8204
|
-
if (
|
|
8314
|
+
if (distance4 <= nextDistance + EPS10) {
|
|
8205
8315
|
const offset = Math.max(
|
|
8206
8316
|
0,
|
|
8207
|
-
Math.min(segmentLength,
|
|
8317
|
+
Math.min(segmentLength, distance4 - pathDistance)
|
|
8208
8318
|
);
|
|
8209
8319
|
const direction = getSegmentDirection(start, end);
|
|
8210
8320
|
return {
|
|
@@ -8329,13 +8439,13 @@ var getCandidateDistances = (traceLength, vertexDistances) => {
|
|
|
8329
8439
|
const distances = /* @__PURE__ */ new Set();
|
|
8330
8440
|
const maxSteps = Math.ceil(traceLength / CANDIDATE_STEP);
|
|
8331
8441
|
for (let i = 0; i <= maxSteps; i++) {
|
|
8332
|
-
const
|
|
8333
|
-
distances.add(roundDistance(
|
|
8442
|
+
const distance4 = Math.min(traceLength, i * CANDIDATE_STEP);
|
|
8443
|
+
distances.add(roundDistance(distance4));
|
|
8334
8444
|
}
|
|
8335
|
-
for (const
|
|
8336
|
-
distances.add(roundDistance(
|
|
8445
|
+
for (const distance4 of vertexDistances) {
|
|
8446
|
+
distances.add(roundDistance(distance4));
|
|
8337
8447
|
}
|
|
8338
|
-
return [...distances].filter((
|
|
8448
|
+
return [...distances].filter((distance4) => distance4 >= -EPS10 && distance4 <= traceLength + EPS10).sort((a, b) => a - b);
|
|
8339
8449
|
};
|
|
8340
8450
|
var getOrientationsForPoint = (params) => {
|
|
8341
8451
|
const { inputProblem, label, point, orientationConstraint } = params;
|
|
@@ -8513,7 +8623,7 @@ var getNetLabelHeight = (inputProblem, label) => {
|
|
|
8513
8623
|
(nc) => nc.pinIds.some((pid) => label.pinIds.includes(pid))
|
|
8514
8624
|
)?.netLabelHeight;
|
|
8515
8625
|
};
|
|
8516
|
-
var roundDistance = (
|
|
8626
|
+
var roundDistance = (distance4) => Number(distance4.toFixed(6));
|
|
8517
8627
|
var isSamePlacement = (label, point, orientation) => Math.abs(point.x - label.anchorPoint.x) <= EPS10 && Math.abs(point.y - label.anchorPoint.y) <= EPS10 && orientation === label.orientation;
|
|
8518
8628
|
|
|
8519
8629
|
// lib/solvers/TraceAnchoredNetLabelOverlapSolver/visualize.ts
|