@tscircuit/schematic-trace-solver 0.0.97 → 0.0.99
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 +10 -0
- package/dist/index.js +1077 -519
- package/lib/solvers/MspConnectionPairSolver/MspConnectionPairSolver.ts +19 -9
- package/lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/SchematicTraceSingleLineSolver2.ts +30 -0
- package/lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/generateEndpointCollisionDetours.ts +84 -0
- package/lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver.ts +45 -1
- package/lib/solvers/TraceCleanupSolver/TraceCleanupSolver.ts +55 -13
- package/lib/solvers/TraceCleanupSolver/alignSameNetRails.ts +66 -0
- package/lib/solvers/TraceCleanupSolver/sameNetRailAlignment/evaluateRailGroup.ts +124 -0
- package/lib/solvers/TraceCleanupSolver/sameNetRailAlignment/geometry.ts +108 -0
- package/lib/solvers/TraceCleanupSolver/sameNetRailAlignment/getComponentSideRailSegments.ts +121 -0
- package/lib/solvers/TraceCleanupSolver/sameNetRailAlignment/getRailGroups.ts +114 -0
- package/lib/solvers/TraceCleanupSolver/sameNetRailAlignment/moveRailSegments.ts +27 -0
- package/lib/solvers/TraceCleanupSolver/sameNetRailAlignment/preservesLabelAnchors.ts +30 -0
- package/lib/solvers/TraceCleanupSolver/sameNetRailAlignment/scoreRailAlignment.ts +67 -0
- package/lib/solvers/TraceCleanupSolver/sameNetRailAlignment/types.ts +34 -0
- package/lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/SingleOverlapSolver/SingleOverlapSolver.ts +1 -60
- package/lib/utils/doesPathCoincideWithTraces.ts +61 -0
- 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/bug-reports/bug-report-20260707T141025Z/__snapshots__/bug-report-20260707T141025Z.snap.svg +1 -1
- package/tests/examples/__snapshots__/example02.snap.svg +1 -1
- package/tests/examples/__snapshots__/example09.snap.svg +9 -13
- package/tests/examples/__snapshots__/example14.snap.svg +1 -1
- package/tests/examples/__snapshots__/example18.snap.svg +1 -1
- package/tests/examples/__snapshots__/example21.snap.svg +30 -32
- package/tests/examples/__snapshots__/example29.snap.svg +13 -19
- package/tests/examples/__snapshots__/example46.snap.svg +1 -1
- package/tests/repros/__snapshots__/repro-cc2340r5.snap.svg +1 -1
- package/tests/repros/__snapshots__/repro-rp2040-gamepad-trace-alignment.snap.svg +1 -1
- package/tests/repros/__snapshots__/repro129-host-custom-symbol-passives.snap.svg +60 -0
- package/tests/repros/__snapshots__/repro130-bq27441-fuel-gauge-trace-through-c1.snap.svg +1 -1
- package/tests/repros/assets/repro129-host-custom-symbol-passives.input.json +94 -0
- package/tests/repros/repro-rp2040-gamepad-trace-alignment.test.ts +24 -0
- package/tests/repros/repro129-host-custom-symbol-passives.test.ts +16 -0
- package/tests/solvers/MspConnectionPairSolver/msp-connection-pair-solver-direct-connection-distance.test.ts +46 -0
- package/tests/solvers/SchematicTraceSingleLineSolver2/generate-endpoint-collision-detours.test.ts +38 -0
- package/tests/solvers/TraceCleanupSolver/alignSameNetRails-component-scope.test.ts +38 -0
- package/tests/solvers/TraceCleanupSolver/alignSameNetRails-eligible-traces.test.ts +28 -0
- package/tests/solvers/TraceCleanupSolver/alignSameNetRails-horizontal.test.ts +62 -0
- package/tests/solvers/TraceCleanupSolver/alignSameNetRails-label-anchor.test.ts +36 -0
- package/tests/solvers/TraceCleanupSolver/alignSameNetRails-label-junction.test.ts +42 -0
- package/tests/solvers/TraceCleanupSolver/alignSameNetRails-obstacle.test.ts +28 -0
- package/tests/solvers/TraceCleanupSolver/alignSameNetRails-pipeline-label-connector.test.ts +52 -0
- package/tests/solvers/TraceCleanupSolver/alignSameNetRails-vertical.test.ts +25 -0
- package/tests/solvers/TraceCleanupSolver/alignSameNetRails-visible-length.test.ts +40 -0
- package/tests/solvers/TraceCleanupSolver/fixtures/alignSameNetRails.ts +89 -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)) {
|
|
@@ -856,8 +861,70 @@ var candidateMidsFromSet = (axis, colliding, collisionRects, aabb, eps = EPS2) =
|
|
|
856
861
|
if (topNeighbor !== void 0) {
|
|
857
862
|
out.push((colliding.maxY + topNeighbor) / 2);
|
|
858
863
|
}
|
|
859
|
-
return out;
|
|
864
|
+
return out;
|
|
865
|
+
}
|
|
866
|
+
};
|
|
867
|
+
|
|
868
|
+
// lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/generateEndpointCollisionDetours.ts
|
|
869
|
+
var getSegmentAxis = (start, end) => {
|
|
870
|
+
if (isVertical(start, end)) return "x";
|
|
871
|
+
if (isHorizontal(start, end)) return "y";
|
|
872
|
+
return null;
|
|
873
|
+
};
|
|
874
|
+
var hasOnlyNonzeroOrthogonalSegments = (path) => path.every((point, index) => {
|
|
875
|
+
const nextPoint = path[index + 1];
|
|
876
|
+
if (!nextPoint) return true;
|
|
877
|
+
if (!isHorizontal(point, nextPoint) && !isVertical(point, nextPoint)) {
|
|
878
|
+
return false;
|
|
879
|
+
}
|
|
880
|
+
return Math.abs(point.x - nextPoint.x) + Math.abs(point.y - nextPoint.y) > 0;
|
|
881
|
+
});
|
|
882
|
+
var generateEndpointCollisionDetours = ({
|
|
883
|
+
path,
|
|
884
|
+
collidingSegmentIndex,
|
|
885
|
+
obstacle
|
|
886
|
+
}) => {
|
|
887
|
+
if (path.length !== 3) return [];
|
|
888
|
+
const lastSegmentIndex = path.length - 2;
|
|
889
|
+
if (collidingSegmentIndex !== 0 && collidingSegmentIndex !== lastSegmentIndex) {
|
|
890
|
+
return [];
|
|
891
|
+
}
|
|
892
|
+
const shouldReverse = collidingSegmentIndex === lastSegmentIndex;
|
|
893
|
+
const orderedPath = shouldReverse ? [...path].reverse() : path;
|
|
894
|
+
const [start, corner, end] = orderedPath;
|
|
895
|
+
const firstSegmentAxis = getSegmentAxis(start, corner);
|
|
896
|
+
const secondSegmentAxis = getSegmentAxis(corner, end);
|
|
897
|
+
if (!firstSegmentAxis || !secondSegmentAxis) return [];
|
|
898
|
+
if (firstSegmentAxis === secondSegmentAxis) return [];
|
|
899
|
+
const escapeCoordinates = [
|
|
900
|
+
...midBetweenPointAndRect(secondSegmentAxis, start, obstacle),
|
|
901
|
+
...midBetweenPointAndRect(secondSegmentAxis, end, obstacle)
|
|
902
|
+
];
|
|
903
|
+
const detourCoordinates = [
|
|
904
|
+
...midBetweenPointAndRect(firstSegmentAxis, start, obstacle),
|
|
905
|
+
...midBetweenPointAndRect(firstSegmentAxis, end, obstacle)
|
|
906
|
+
];
|
|
907
|
+
const detours = [];
|
|
908
|
+
for (const escapeCoordinate of [...new Set(escapeCoordinates)]) {
|
|
909
|
+
for (const detourCoordinate of [...new Set(detourCoordinates)]) {
|
|
910
|
+
const orderedDetour = firstSegmentAxis === "y" ? [
|
|
911
|
+
start,
|
|
912
|
+
{ x: escapeCoordinate, y: start.y },
|
|
913
|
+
{ x: escapeCoordinate, y: detourCoordinate },
|
|
914
|
+
{ x: end.x, y: detourCoordinate },
|
|
915
|
+
end
|
|
916
|
+
] : [
|
|
917
|
+
start,
|
|
918
|
+
{ x: start.x, y: escapeCoordinate },
|
|
919
|
+
{ x: detourCoordinate, y: escapeCoordinate },
|
|
920
|
+
{ x: detourCoordinate, y: end.y },
|
|
921
|
+
end
|
|
922
|
+
];
|
|
923
|
+
const detour = shouldReverse ? orderedDetour.reverse() : orderedDetour;
|
|
924
|
+
if (hasOnlyNonzeroOrthogonalSegments(detour)) detours.push(detour);
|
|
925
|
+
}
|
|
860
926
|
}
|
|
927
|
+
return detours;
|
|
861
928
|
};
|
|
862
929
|
|
|
863
930
|
// lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/pathOps.ts
|
|
@@ -1210,6 +1277,29 @@ var SchematicTraceSingleLineSolver2 = class extends BaseSolver {
|
|
|
1210
1277
|
let { segIndex, rect } = collision;
|
|
1211
1278
|
const isFirstSegment = segIndex === 0;
|
|
1212
1279
|
const isLastSegment = segIndex === path.length - 2;
|
|
1280
|
+
if (path.length === 3 && (isFirstSegment || isLastSegment)) {
|
|
1281
|
+
const detours = generateEndpointCollisionDetours({
|
|
1282
|
+
path,
|
|
1283
|
+
collidingSegmentIndex: segIndex,
|
|
1284
|
+
obstacle: rect
|
|
1285
|
+
}).filter((detour) => {
|
|
1286
|
+
const key = pathKey(detour);
|
|
1287
|
+
if (this.visited.has(key)) return false;
|
|
1288
|
+
this.visited.add(key);
|
|
1289
|
+
return true;
|
|
1290
|
+
}).sort(
|
|
1291
|
+
(a2, b2) => this.pathLength(a2) - this.pathLength(b2) || this.getPinBandPenalty(a2) - this.getPinBandPenalty(b2)
|
|
1292
|
+
);
|
|
1293
|
+
for (const detour of detours) {
|
|
1294
|
+
const nextCollisionRects = new Set(collisionRects);
|
|
1295
|
+
nextCollisionRects.add(rect);
|
|
1296
|
+
this.queue.push({
|
|
1297
|
+
path: detour,
|
|
1298
|
+
collisionRects: nextCollisionRects
|
|
1299
|
+
});
|
|
1300
|
+
}
|
|
1301
|
+
return;
|
|
1302
|
+
}
|
|
1213
1303
|
if (isFirstSegment) {
|
|
1214
1304
|
if (path.length < 3) {
|
|
1215
1305
|
return;
|
|
@@ -1440,12 +1530,12 @@ var applyJogToTerminalSegment = ({
|
|
|
1440
1530
|
if (si !== 0 && si !== pts.length - 2) return;
|
|
1441
1531
|
const start = pts[si];
|
|
1442
1532
|
const end = pts[si + 1];
|
|
1443
|
-
const
|
|
1444
|
-
const
|
|
1445
|
-
if (!
|
|
1446
|
-
const segDir =
|
|
1533
|
+
const isVertical5 = Math.abs(start.x - end.x) < EPS11;
|
|
1534
|
+
const isHorizontal4 = Math.abs(start.y - end.y) < EPS11;
|
|
1535
|
+
if (!isVertical5 && !isHorizontal4) return;
|
|
1536
|
+
const segDir = isVertical5 ? end.y > start.y ? 1 : -1 : end.x > start.x ? 1 : -1;
|
|
1447
1537
|
if (pts.length === 2) {
|
|
1448
|
-
if (
|
|
1538
|
+
if (isVertical5) {
|
|
1449
1539
|
const jogYNearStart = start.y + segDir * JOG_SIZE;
|
|
1450
1540
|
const jogYNearEnd = end.y - segDir * JOG_SIZE;
|
|
1451
1541
|
pts.splice(
|
|
@@ -1471,7 +1561,7 @@ var applyJogToTerminalSegment = ({
|
|
|
1471
1561
|
return;
|
|
1472
1562
|
}
|
|
1473
1563
|
if (si === 0) {
|
|
1474
|
-
if (
|
|
1564
|
+
if (isVertical5) {
|
|
1475
1565
|
const jogY = start.y + segDir * JOG_SIZE;
|
|
1476
1566
|
pts.splice(
|
|
1477
1567
|
1,
|
|
@@ -1491,7 +1581,7 @@ var applyJogToTerminalSegment = ({
|
|
|
1491
1581
|
);
|
|
1492
1582
|
}
|
|
1493
1583
|
} else {
|
|
1494
|
-
if (
|
|
1584
|
+
if (isVertical5) {
|
|
1495
1585
|
const jogY = end.y - segDir * JOG_SIZE;
|
|
1496
1586
|
pts.splice(
|
|
1497
1587
|
si,
|
|
@@ -1587,10 +1677,10 @@ var TraceOverlapIssueSolver = class extends BaseSolver {
|
|
|
1587
1677
|
} else {
|
|
1588
1678
|
const start = pts[si];
|
|
1589
1679
|
const end = pts[si + 1];
|
|
1590
|
-
const
|
|
1591
|
-
const
|
|
1592
|
-
if (!
|
|
1593
|
-
if (
|
|
1680
|
+
const isVertical5 = Math.abs(start.x - end.x) < EPS4;
|
|
1681
|
+
const isHorizontal4 = Math.abs(start.y - end.y) < EPS4;
|
|
1682
|
+
if (!isVertical5 && !isHorizontal4) continue;
|
|
1683
|
+
if (isVertical5) {
|
|
1594
1684
|
start.x += offset;
|
|
1595
1685
|
end.x += offset;
|
|
1596
1686
|
} else {
|
|
@@ -1619,11 +1709,11 @@ var TraceOverlapIssueSolver = class extends BaseSolver {
|
|
|
1619
1709
|
}) {
|
|
1620
1710
|
const blockingCollisions = this.getBlockingCollisions({ group, offset });
|
|
1621
1711
|
if (blockingCollisions.length === 0) return offset;
|
|
1622
|
-
const crossesThroughObstacle = (candidateOffset) => blockingCollisions.some(({ start, isVertical:
|
|
1712
|
+
const crossesThroughObstacle = (candidateOffset) => blockingCollisions.some(({ start, isVertical: isVertical5, obstacle }) => {
|
|
1623
1713
|
let orig;
|
|
1624
1714
|
let min;
|
|
1625
1715
|
let max;
|
|
1626
|
-
if (
|
|
1716
|
+
if (isVertical5) {
|
|
1627
1717
|
orig = start.x;
|
|
1628
1718
|
min = obstacle.minX;
|
|
1629
1719
|
max = obstacle.maxX;
|
|
@@ -1635,8 +1725,8 @@ var TraceOverlapIssueSolver = class extends BaseSolver {
|
|
|
1635
1725
|
const next = orig + candidateOffset;
|
|
1636
1726
|
return orig <= min + EPS4 && next >= max - EPS4 || orig >= max - EPS4 && next <= min + EPS4;
|
|
1637
1727
|
});
|
|
1638
|
-
const edges = blockingCollisions.map(({ start, isVertical:
|
|
1639
|
-
if (
|
|
1728
|
+
const edges = blockingCollisions.map(({ start, isVertical: isVertical5, obstacle }) => {
|
|
1729
|
+
if (isVertical5) {
|
|
1640
1730
|
return {
|
|
1641
1731
|
coord: start.x,
|
|
1642
1732
|
lowEdge: obstacle.minX,
|
|
@@ -1670,10 +1760,10 @@ var TraceOverlapIssueSolver = class extends BaseSolver {
|
|
|
1670
1760
|
const start = trace.tracePath[traceSegmentIndex];
|
|
1671
1761
|
const end = trace.tracePath[traceSegmentIndex + 1];
|
|
1672
1762
|
if (!start || !end) continue;
|
|
1673
|
-
const
|
|
1674
|
-
const
|
|
1675
|
-
if (!
|
|
1676
|
-
const shiftedSegment =
|
|
1763
|
+
const isVertical5 = Math.abs(start.x - end.x) < EPS4;
|
|
1764
|
+
const isHorizontal4 = Math.abs(start.y - end.y) < EPS4;
|
|
1765
|
+
if (!isVertical5 && !isHorizontal4) continue;
|
|
1766
|
+
const shiftedSegment = isVertical5 ? [
|
|
1677
1767
|
{ ...start, x: start.x + offset },
|
|
1678
1768
|
{ ...end, x: end.x + offset }
|
|
1679
1769
|
] : [
|
|
@@ -1684,7 +1774,7 @@ var TraceOverlapIssueSolver = class extends BaseSolver {
|
|
|
1684
1774
|
if (collision) {
|
|
1685
1775
|
blockingCollisions.push({
|
|
1686
1776
|
start,
|
|
1687
|
-
isVertical:
|
|
1777
|
+
isVertical: isVertical5,
|
|
1688
1778
|
obstacle: collision.rect
|
|
1689
1779
|
});
|
|
1690
1780
|
}
|
|
@@ -1867,9 +1957,9 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
1867
1957
|
for (let i = 0; i < tracePath.length - 1; i++) {
|
|
1868
1958
|
const p1 = tracePath[i];
|
|
1869
1959
|
const p2 = tracePath[i + 1];
|
|
1870
|
-
const
|
|
1871
|
-
const
|
|
1872
|
-
if (!
|
|
1960
|
+
const isHorizontal4 = Math.abs(p1.y - p2.y) < EPS11;
|
|
1961
|
+
const isVertical5 = Math.abs(p1.x - p2.x) < EPS11;
|
|
1962
|
+
if (!isHorizontal4 && !isVertical5) {
|
|
1873
1963
|
return { mspPairId, tracePath, i, p1, p2 };
|
|
1874
1964
|
}
|
|
1875
1965
|
}
|
|
@@ -2961,7 +3051,7 @@ var mergeLabelGroup = (group, groupKey) => {
|
|
|
2961
3051
|
};
|
|
2962
3052
|
|
|
2963
3053
|
// lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/LabelMergingSolver/filterLabelsAtTraceEdges.ts
|
|
2964
|
-
import { distance } from "@tscircuit/math-utils";
|
|
3054
|
+
import { distance as distance2 } from "@tscircuit/math-utils";
|
|
2965
3055
|
var filterLabelsAtTraceEdges = ({
|
|
2966
3056
|
labels,
|
|
2967
3057
|
traces,
|
|
@@ -2994,8 +3084,8 @@ var filterLabelsAtTraceEdges = ({
|
|
|
2994
3084
|
if (trace.tracePath.length === 0) continue;
|
|
2995
3085
|
const startPoint = trace.tracePath[0];
|
|
2996
3086
|
const endPoint = trace.tracePath[trace.tracePath.length - 1];
|
|
2997
|
-
const startDist =
|
|
2998
|
-
const endDist =
|
|
3087
|
+
const startDist = distance2(label.center, startPoint);
|
|
3088
|
+
const endDist = distance2(label.center, endPoint);
|
|
2999
3089
|
if (startDist <= distanceThreshold || endDist <= distanceThreshold) {
|
|
3000
3090
|
isNearTraceEdge = true;
|
|
3001
3091
|
break;
|
|
@@ -3478,19 +3568,18 @@ var generateRerouteCandidates = ({
|
|
|
3478
3568
|
return [...fourPointCandidates, ...snipReconnectCandidates];
|
|
3479
3569
|
};
|
|
3480
3570
|
|
|
3481
|
-
// lib/
|
|
3482
|
-
var MAX_TRIES = 5;
|
|
3571
|
+
// lib/utils/doesPathCoincideWithTraces.ts
|
|
3483
3572
|
var COINCIDENT_EPS = 2e-3;
|
|
3484
3573
|
var doesPathCoincideWithTraces = (path, traces) => {
|
|
3485
3574
|
const rangesOverlap1D = (a1, a2, b1, b2) => Math.min(Math.max(a1, a2), Math.max(b1, b2)) - Math.max(Math.min(a1, a2), Math.min(b1, b2)) > COINCIDENT_EPS;
|
|
3486
3575
|
for (let i = 0; i < path.length - 1; i++) {
|
|
3487
3576
|
const pathSegStart = path[i];
|
|
3488
3577
|
const pathSegEnd = path[i + 1];
|
|
3489
|
-
const
|
|
3490
|
-
const
|
|
3491
|
-
if (!
|
|
3492
|
-
const crossAxis =
|
|
3493
|
-
const alongAxis =
|
|
3578
|
+
const isVertical5 = Math.abs(pathSegStart.x - pathSegEnd.x) < COINCIDENT_EPS;
|
|
3579
|
+
const isHorizontal4 = Math.abs(pathSegStart.y - pathSegEnd.y) < COINCIDENT_EPS;
|
|
3580
|
+
if (!isVertical5 && !isHorizontal4) continue;
|
|
3581
|
+
const crossAxis = isVertical5 ? "x" : "y";
|
|
3582
|
+
const alongAxis = isVertical5 ? "y" : "x";
|
|
3494
3583
|
for (const trace of traces) {
|
|
3495
3584
|
for (let j = 0; j < trace.tracePath.length - 1; j++) {
|
|
3496
3585
|
const traceSegStart = trace.tracePath[j];
|
|
@@ -3512,6 +3601,9 @@ var doesPathCoincideWithTraces = (path, traces) => {
|
|
|
3512
3601
|
}
|
|
3513
3602
|
return false;
|
|
3514
3603
|
};
|
|
3604
|
+
|
|
3605
|
+
// lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/SingleOverlapSolver/SingleOverlapSolver.ts
|
|
3606
|
+
var MAX_TRIES = 5;
|
|
3515
3607
|
var SingleOverlapSolver = class extends BaseSolver {
|
|
3516
3608
|
queuedCandidatePaths;
|
|
3517
3609
|
solvedTracePath = null;
|
|
@@ -4075,7 +4167,7 @@ function doesTraceOverlapWithExistingTraces(newTracePath, existingTraces) {
|
|
|
4075
4167
|
|
|
4076
4168
|
// lib/solvers/LongDistancePairSolver/LongDistancePairSolver.ts
|
|
4077
4169
|
var NEAREST_NEIGHBOR_COUNT = 3;
|
|
4078
|
-
var
|
|
4170
|
+
var distance3 = (p1, p2) => {
|
|
4079
4171
|
return Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2));
|
|
4080
4172
|
};
|
|
4081
4173
|
var LongDistancePairSolver = class extends BaseSolver {
|
|
@@ -4116,7 +4208,7 @@ var LongDistancePairSolver = class extends BaseSolver {
|
|
|
4116
4208
|
return [
|
|
4117
4209
|
{
|
|
4118
4210
|
pin: targetPin,
|
|
4119
|
-
distance:
|
|
4211
|
+
distance: distance3(sourcePin, targetPin)
|
|
4120
4212
|
}
|
|
4121
4213
|
];
|
|
4122
4214
|
}).sort((a, b) => a.distance - b.distance).slice(0, NEAREST_NEIGHBOR_COUNT);
|
|
@@ -4668,26 +4760,610 @@ var balanceZShapes = ({
|
|
|
4668
4760
|
if (Math.abs(len1Original - len2Original) < 1e-3) {
|
|
4669
4761
|
continue;
|
|
4670
4762
|
}
|
|
4671
|
-
if (isHVHZShape) {
|
|
4672
|
-
const idealX = (p1.x + p4.x) / 2;
|
|
4673
|
-
p2New = { x: idealX, y: p2.y };
|
|
4674
|
-
p3New = { x: idealX, y: p3.y };
|
|
4675
|
-
} else {
|
|
4676
|
-
const idealY = (p1.y + p4.y) / 2;
|
|
4677
|
-
p2New = { x: p2.x, y: idealY };
|
|
4678
|
-
p3New = { x: p3.x, y: idealY };
|
|
4679
|
-
}
|
|
4680
|
-
const collides = segmentIntersectsAnyRect(p1, p2New, combinedObstacles) || segmentIntersectsAnyRect(p2New, p3New, combinedObstacles) || segmentIntersectsAnyRect(p3New, p4, combinedObstacles) || segmentIntersectsAnyRect(p1, p2New, labelBounds) || segmentIntersectsAnyRect(p2New, p3New, labelBounds) || segmentIntersectsAnyRect(p3New, p4, labelBounds);
|
|
4681
|
-
if (!collides) {
|
|
4682
|
-
newPath[i + 1] = p2New;
|
|
4683
|
-
newPath[i + 2] = p3New;
|
|
4684
|
-
i = 0;
|
|
4763
|
+
if (isHVHZShape) {
|
|
4764
|
+
const idealX = (p1.x + p4.x) / 2;
|
|
4765
|
+
p2New = { x: idealX, y: p2.y };
|
|
4766
|
+
p3New = { x: idealX, y: p3.y };
|
|
4767
|
+
} else {
|
|
4768
|
+
const idealY = (p1.y + p4.y) / 2;
|
|
4769
|
+
p2New = { x: p2.x, y: idealY };
|
|
4770
|
+
p3New = { x: p3.x, y: idealY };
|
|
4771
|
+
}
|
|
4772
|
+
const collides = segmentIntersectsAnyRect(p1, p2New, combinedObstacles) || segmentIntersectsAnyRect(p2New, p3New, combinedObstacles) || segmentIntersectsAnyRect(p3New, p4, combinedObstacles) || segmentIntersectsAnyRect(p1, p2New, labelBounds) || segmentIntersectsAnyRect(p2New, p3New, labelBounds) || segmentIntersectsAnyRect(p3New, p4, labelBounds);
|
|
4773
|
+
if (!collides) {
|
|
4774
|
+
newPath[i + 1] = p2New;
|
|
4775
|
+
newPath[i + 2] = p3New;
|
|
4776
|
+
i = 0;
|
|
4777
|
+
}
|
|
4778
|
+
}
|
|
4779
|
+
const finalSimplifiedPath = simplifyPath(newPath);
|
|
4780
|
+
return {
|
|
4781
|
+
...targetTrace,
|
|
4782
|
+
tracePath: finalSimplifiedPath
|
|
4783
|
+
};
|
|
4784
|
+
};
|
|
4785
|
+
|
|
4786
|
+
// lib/solvers/TraceCleanupSolver/sameNetRailAlignment/geometry.ts
|
|
4787
|
+
var RAIL_ALIGNMENT_EPSILON = 2e-3;
|
|
4788
|
+
var nearlyEqual = (a, b) => Math.abs(a - b) < RAIL_ALIGNMENT_EPSILON;
|
|
4789
|
+
var isHorizontal2 = (a, b) => nearlyEqual(a.y, b.y);
|
|
4790
|
+
var isVertical2 = (a, b) => nearlyEqual(a.x, b.x);
|
|
4791
|
+
var isPositiveLength = (a, b) => Math.abs(a.x - b.x) >= RAIL_ALIGNMENT_EPSILON || Math.abs(a.y - b.y) >= RAIL_ALIGNMENT_EPSILON;
|
|
4792
|
+
var getRailOrientation = (a, b) => {
|
|
4793
|
+
if (!isPositiveLength(a, b)) return null;
|
|
4794
|
+
if (isVertical2(a, b)) return "vertical";
|
|
4795
|
+
if (isHorizontal2(a, b)) return "horizontal";
|
|
4796
|
+
return null;
|
|
4797
|
+
};
|
|
4798
|
+
var rangesTouchOrOverlap = (a, b) => Math.min(a.maxAlong, b.maxAlong) - Math.max(a.minAlong, b.minAlong) >= -RAIL_ALIGNMENT_EPSILON;
|
|
4799
|
+
var pointsEqual = (a, b) => nearlyEqual(a.x, b.x) && nearlyEqual(a.y, b.y);
|
|
4800
|
+
var getDistinctCoordinates = (coordinates) => {
|
|
4801
|
+
const distinct = [];
|
|
4802
|
+
for (const coordinate of coordinates) {
|
|
4803
|
+
if (!distinct.some((item) => nearlyEqual(item, coordinate))) {
|
|
4804
|
+
distinct.push(coordinate);
|
|
4805
|
+
}
|
|
4806
|
+
}
|
|
4807
|
+
return distinct;
|
|
4808
|
+
};
|
|
4809
|
+
var getMergedIntervalLength = (intervals) => {
|
|
4810
|
+
const groups = [];
|
|
4811
|
+
for (const interval of intervals) {
|
|
4812
|
+
const group = groups.find(
|
|
4813
|
+
(items) => nearlyEqual(items[0].coordinate, interval.coordinate)
|
|
4814
|
+
);
|
|
4815
|
+
if (group) group.push(interval);
|
|
4816
|
+
else groups.push([interval]);
|
|
4817
|
+
}
|
|
4818
|
+
return groups.reduce((total, group) => {
|
|
4819
|
+
const sorted = [...group].sort((a, b) => a.min - b.min);
|
|
4820
|
+
let groupLength = 0;
|
|
4821
|
+
let currentMin = sorted[0].min;
|
|
4822
|
+
let currentMax = sorted[0].max;
|
|
4823
|
+
for (const interval of sorted.slice(1)) {
|
|
4824
|
+
if (interval.min <= currentMax + RAIL_ALIGNMENT_EPSILON) {
|
|
4825
|
+
currentMax = Math.max(currentMax, interval.max);
|
|
4826
|
+
} else {
|
|
4827
|
+
groupLength += currentMax - currentMin;
|
|
4828
|
+
currentMin = interval.min;
|
|
4829
|
+
currentMax = interval.max;
|
|
4830
|
+
}
|
|
4831
|
+
}
|
|
4832
|
+
return total + groupLength + currentMax - currentMin;
|
|
4833
|
+
}, 0);
|
|
4834
|
+
};
|
|
4835
|
+
var getVisibleTraceLength = (traces) => {
|
|
4836
|
+
const horizontal = [];
|
|
4837
|
+
const vertical = [];
|
|
4838
|
+
for (const trace of traces) {
|
|
4839
|
+
for (let index = 0; index < trace.tracePath.length - 1; index++) {
|
|
4840
|
+
const start = trace.tracePath[index];
|
|
4841
|
+
const end = trace.tracePath[index + 1];
|
|
4842
|
+
if (isHorizontal2(start, end)) {
|
|
4843
|
+
horizontal.push({
|
|
4844
|
+
coordinate: start.y,
|
|
4845
|
+
min: Math.min(start.x, end.x),
|
|
4846
|
+
max: Math.max(start.x, end.x)
|
|
4847
|
+
});
|
|
4848
|
+
} else if (isVertical2(start, end)) {
|
|
4849
|
+
vertical.push({
|
|
4850
|
+
coordinate: start.x,
|
|
4851
|
+
min: Math.min(start.y, end.y),
|
|
4852
|
+
max: Math.max(start.y, end.y)
|
|
4853
|
+
});
|
|
4854
|
+
}
|
|
4855
|
+
}
|
|
4856
|
+
}
|
|
4857
|
+
return getMergedIntervalLength(horizontal) + getMergedIntervalLength(vertical);
|
|
4858
|
+
};
|
|
4859
|
+
|
|
4860
|
+
// lib/solvers/TraceCleanupSolver/sameNetRailAlignment/moveRailSegments.ts
|
|
4861
|
+
var moveRailSegments = (trace, segments, coordinate) => {
|
|
4862
|
+
const pointsToMove = /* @__PURE__ */ new Set();
|
|
4863
|
+
for (const segment of segments) {
|
|
4864
|
+
pointsToMove.add(segment.segmentIndex);
|
|
4865
|
+
pointsToMove.add(segment.segmentIndex + 1);
|
|
4866
|
+
}
|
|
4867
|
+
const orientation = segments[0].orientation;
|
|
4868
|
+
const tracePath = simplifyPath(
|
|
4869
|
+
trace.tracePath.map((point, index) => {
|
|
4870
|
+
if (!pointsToMove.has(index)) return point;
|
|
4871
|
+
return orientation === "vertical" ? { ...point, x: coordinate } : { ...point, y: coordinate };
|
|
4872
|
+
})
|
|
4873
|
+
);
|
|
4874
|
+
return { ...trace, tracePath };
|
|
4875
|
+
};
|
|
4876
|
+
|
|
4877
|
+
// lib/solvers/RailNetLabelCornerPlacementSolver/geometry.ts
|
|
4878
|
+
var EPS5 = 1e-6;
|
|
4879
|
+
var isTraceLine = (trace) => getUniquePinCount(trace.pinIds) >= 2;
|
|
4880
|
+
var rectsOverlap = (a, b) => Math.min(a.maxX, b.maxX) - Math.max(a.minX, b.minX) > EPS5 && Math.min(a.maxY, b.maxY) - Math.max(a.minY, b.minY) > EPS5;
|
|
4881
|
+
var getTraceCorners = (path) => {
|
|
4882
|
+
const corners = [];
|
|
4883
|
+
for (let i = 1; i < path.length - 1; i++) {
|
|
4884
|
+
const previousPoint = path[i - 1];
|
|
4885
|
+
const cornerPoint = path[i];
|
|
4886
|
+
const nextPoint = path[i + 1];
|
|
4887
|
+
if (isTraceCorner(previousPoint, cornerPoint, nextPoint)) {
|
|
4888
|
+
corners.push(cornerPoint);
|
|
4889
|
+
}
|
|
4890
|
+
}
|
|
4891
|
+
return corners;
|
|
4892
|
+
};
|
|
4893
|
+
var tracePathContainsPoint = (path, point) => {
|
|
4894
|
+
for (let i = 0; i < path.length - 1; i++) {
|
|
4895
|
+
if (isPointOnSegment(point, path[i], path[i + 1])) return true;
|
|
4896
|
+
}
|
|
4897
|
+
return false;
|
|
4898
|
+
};
|
|
4899
|
+
var getDistance = (a, b) => Math.abs(a.x - b.x) + Math.abs(a.y - b.y);
|
|
4900
|
+
var getUniquePinCount = (pinIds) => new Set(pinIds).size;
|
|
4901
|
+
var isTraceCorner = (a, b, c) => getSegmentOrientation(a, b) !== getSegmentOrientation(b, c);
|
|
4902
|
+
var isPointOnSegment = (point, start, end) => {
|
|
4903
|
+
if (getSegmentOrientation(start, end) === "horizontal") {
|
|
4904
|
+
return Math.abs(point.y - start.y) <= EPS5 && point.x >= Math.min(start.x, end.x) - EPS5 && point.x <= Math.max(start.x, end.x) + EPS5;
|
|
4905
|
+
}
|
|
4906
|
+
return Math.abs(point.x - start.x) <= EPS5 && point.y >= Math.min(start.y, end.y) - EPS5 && point.y <= Math.max(start.y, end.y) + EPS5;
|
|
4907
|
+
};
|
|
4908
|
+
var getSegmentOrientation = (a, b) => Math.abs(a.y - b.y) <= EPS5 ? "horizontal" : "vertical";
|
|
4909
|
+
|
|
4910
|
+
// lib/solvers/TraceCleanupSolver/sameNetRailAlignment/preservesLabelAnchors.ts
|
|
4911
|
+
var getAnchoredTraceIds = (label, traces) => new Set(
|
|
4912
|
+
traces.filter(
|
|
4913
|
+
(trace) => trace.globalConnNetId === label.globalConnNetId && tracePathContainsPoint(trace.tracePath, label.anchorPoint)
|
|
4914
|
+
).map((trace) => trace.mspPairId)
|
|
4915
|
+
);
|
|
4916
|
+
var preservesLabelAnchors = (labels, before, after) => labels.every((label) => {
|
|
4917
|
+
const anchoredBefore = getAnchoredTraceIds(label, before);
|
|
4918
|
+
if (anchoredBefore.size === 0) return true;
|
|
4919
|
+
const anchoredAfter = getAnchoredTraceIds(label, after);
|
|
4920
|
+
return [...anchoredBefore].every((traceId) => anchoredAfter.has(traceId));
|
|
4921
|
+
});
|
|
4922
|
+
|
|
4923
|
+
// lib/solvers/Example28Solver/types.ts
|
|
4924
|
+
var EPS6 = 1e-9;
|
|
4925
|
+
|
|
4926
|
+
// lib/solvers/Example28Solver/segmentRunsAlongRectBoundary.ts
|
|
4927
|
+
var segmentRunsAlongRectBoundary = (start, end, rect) => {
|
|
4928
|
+
const isVertical5 = Math.abs(start.x - end.x) < EPS6;
|
|
4929
|
+
const isHorizontal4 = Math.abs(start.y - end.y) < EPS6;
|
|
4930
|
+
if (isVertical5) {
|
|
4931
|
+
return Math.abs(start.x - rect.minX) < EPS6 || Math.abs(start.x - rect.maxX) < EPS6;
|
|
4932
|
+
}
|
|
4933
|
+
if (isHorizontal4) {
|
|
4934
|
+
return Math.abs(start.y - rect.minY) < EPS6 || Math.abs(start.y - rect.maxY) < EPS6;
|
|
4935
|
+
}
|
|
4936
|
+
return false;
|
|
4937
|
+
};
|
|
4938
|
+
|
|
4939
|
+
// lib/solvers/Example28Solver/geometry.ts
|
|
4940
|
+
var getPathKey = (path) => path.map((point) => `${point.x},${point.y}`).join(";");
|
|
4941
|
+
var getPathLength = (path) => {
|
|
4942
|
+
let length = 0;
|
|
4943
|
+
for (let i = 0; i < path.length - 1; i++) {
|
|
4944
|
+
length += Math.abs(path[i + 1].x - path[i].x) + Math.abs(path[i + 1].y - path[i].y);
|
|
4945
|
+
}
|
|
4946
|
+
return length;
|
|
4947
|
+
};
|
|
4948
|
+
var getDistance2 = (a, b) => Math.abs(a.x - b.x) + Math.abs(a.y - b.y);
|
|
4949
|
+
var isAxisAlignedSegment = (start, end) => Math.abs(start.x - end.x) < EPS6 || Math.abs(start.y - end.y) < EPS6;
|
|
4950
|
+
var getSegmentOrientation2 = (start, end) => Math.abs(start.y - end.y) < EPS6 ? "horizontal" : "vertical";
|
|
4951
|
+
var projectPointToSegment = (point, start, end) => {
|
|
4952
|
+
if (Math.abs(start.x - end.x) < EPS6) {
|
|
4953
|
+
return {
|
|
4954
|
+
x: start.x,
|
|
4955
|
+
y: Math.min(
|
|
4956
|
+
Math.max(point.y, Math.min(start.y, end.y)),
|
|
4957
|
+
Math.max(start.y, end.y)
|
|
4958
|
+
)
|
|
4959
|
+
};
|
|
4960
|
+
}
|
|
4961
|
+
if (Math.abs(start.y - end.y) < EPS6) {
|
|
4962
|
+
return {
|
|
4963
|
+
x: Math.min(
|
|
4964
|
+
Math.max(point.x, Math.min(start.x, end.x)),
|
|
4965
|
+
Math.max(start.x, end.x)
|
|
4966
|
+
),
|
|
4967
|
+
y: start.y
|
|
4968
|
+
};
|
|
4969
|
+
}
|
|
4970
|
+
return start;
|
|
4971
|
+
};
|
|
4972
|
+
var getPointToSegmentDistance = (point, start, end) => getDistance2(point, projectPointToSegment(point, start, end));
|
|
4973
|
+
var getSegments = (path) => {
|
|
4974
|
+
const segments = [];
|
|
4975
|
+
for (let i = 0; i < path.length - 1; i++) {
|
|
4976
|
+
const start = path[i];
|
|
4977
|
+
const end = path[i + 1];
|
|
4978
|
+
if (!isAxisAlignedSegment(start, end)) continue;
|
|
4979
|
+
segments.push({
|
|
4980
|
+
start,
|
|
4981
|
+
end,
|
|
4982
|
+
orientation: getSegmentOrientation2(start, end)
|
|
4983
|
+
});
|
|
4984
|
+
}
|
|
4985
|
+
return segments;
|
|
4986
|
+
};
|
|
4987
|
+
var findSegmentContainingPoint = (path, point) => {
|
|
4988
|
+
for (let i = 0; i < path.length - 1; i++) {
|
|
4989
|
+
const start = path[i];
|
|
4990
|
+
const end = path[i + 1];
|
|
4991
|
+
if (!isAxisAlignedSegment(start, end)) continue;
|
|
4992
|
+
if (getPointToSegmentDistance(point, start, end) > 1e-6) continue;
|
|
4993
|
+
return {
|
|
4994
|
+
index: i,
|
|
4995
|
+
start,
|
|
4996
|
+
end,
|
|
4997
|
+
orientation: getSegmentOrientation2(start, end)
|
|
4998
|
+
};
|
|
4999
|
+
}
|
|
5000
|
+
return null;
|
|
5001
|
+
};
|
|
5002
|
+
var isPointWithinSegmentPrimaryRange = (point, segment) => {
|
|
5003
|
+
if (segment.orientation === "horizontal") {
|
|
5004
|
+
return point.x >= Math.min(segment.start.x, segment.end.x) - EPS6 && point.x <= Math.max(segment.start.x, segment.end.x) + EPS6;
|
|
5005
|
+
}
|
|
5006
|
+
return point.y >= Math.min(segment.start.y, segment.end.y) - EPS6 && point.y <= Math.max(segment.start.y, segment.end.y) + EPS6;
|
|
5007
|
+
};
|
|
5008
|
+
var findPreferredReroutedSegment = (path, originalSegmentIndex, originalSegmentCount, orientation, anchorPoint) => {
|
|
5009
|
+
const matchingSegments = getSegments(path).filter(
|
|
5010
|
+
(segment) => segment.orientation === orientation
|
|
5011
|
+
);
|
|
5012
|
+
if (matchingSegments.length === 0) return null;
|
|
5013
|
+
const containingSegments = matchingSegments.filter(
|
|
5014
|
+
(segment) => isPointWithinSegmentPrimaryRange(anchorPoint, segment)
|
|
5015
|
+
);
|
|
5016
|
+
const candidateSegments = containingSegments.length > 0 ? containingSegments : matchingSegments;
|
|
5017
|
+
const isNearStart = originalSegmentIndex < originalSegmentCount / 2;
|
|
5018
|
+
return isNearStart ? candidateSegments[0] : candidateSegments[candidateSegments.length - 1];
|
|
5019
|
+
};
|
|
5020
|
+
var projectPointToPath = (point, path) => {
|
|
5021
|
+
let bestPoint = null;
|
|
5022
|
+
let bestDistance = Number.POSITIVE_INFINITY;
|
|
5023
|
+
for (let i = 0; i < path.length - 1; i++) {
|
|
5024
|
+
const projectedPoint = projectPointToSegment(point, path[i], path[i + 1]);
|
|
5025
|
+
const distance4 = getDistance2(point, projectedPoint);
|
|
5026
|
+
if (distance4 < bestDistance) {
|
|
5027
|
+
bestPoint = projectedPoint;
|
|
5028
|
+
bestDistance = distance4;
|
|
5029
|
+
}
|
|
5030
|
+
}
|
|
5031
|
+
return bestPoint;
|
|
5032
|
+
};
|
|
5033
|
+
var segmentsIntersect = (a1, a2, b1, b2) => {
|
|
5034
|
+
const aVertical = Math.abs(a1.x - a2.x) < EPS6;
|
|
5035
|
+
const bVertical = Math.abs(b1.x - b2.x) < EPS6;
|
|
5036
|
+
const between = (value, p1, p2) => value >= Math.min(p1, p2) - EPS6 && value <= Math.max(p1, p2) + EPS6;
|
|
5037
|
+
if (aVertical && bVertical) {
|
|
5038
|
+
if (Math.abs(a1.x - b1.x) > EPS6) return false;
|
|
5039
|
+
const overlap = Math.min(Math.max(a1.y, a2.y), Math.max(b1.y, b2.y)) - Math.max(Math.min(a1.y, a2.y), Math.min(b1.y, b2.y));
|
|
5040
|
+
return overlap > EPS6;
|
|
5041
|
+
}
|
|
5042
|
+
if (!aVertical && !bVertical) {
|
|
5043
|
+
if (Math.abs(a1.y - b1.y) > EPS6) return false;
|
|
5044
|
+
const overlap = Math.min(Math.max(a1.x, a2.x), Math.max(b1.x, b2.x)) - Math.max(Math.min(a1.x, a2.x), Math.min(b1.x, b2.x));
|
|
5045
|
+
return overlap > EPS6;
|
|
5046
|
+
}
|
|
5047
|
+
const verticalA = aVertical ? a1 : b1;
|
|
5048
|
+
const verticalB = aVertical ? a2 : b2;
|
|
5049
|
+
const horizontalA = aVertical ? b1 : a1;
|
|
5050
|
+
const horizontalB = aVertical ? b2 : a2;
|
|
5051
|
+
return between(verticalA.x, horizontalA.x, horizontalB.x) && between(horizontalA.y, verticalA.y, verticalB.y);
|
|
5052
|
+
};
|
|
5053
|
+
var countPathIntersections = (pathA, pathB) => {
|
|
5054
|
+
let count = 0;
|
|
5055
|
+
for (let i = 0; i < pathA.length - 1; i++) {
|
|
5056
|
+
for (let j = 0; j < pathB.length - 1; j++) {
|
|
5057
|
+
if (segmentsIntersect(pathA[i], pathA[i + 1], pathB[j], pathB[j + 1])) {
|
|
5058
|
+
count++;
|
|
5059
|
+
}
|
|
5060
|
+
}
|
|
5061
|
+
}
|
|
5062
|
+
return count;
|
|
5063
|
+
};
|
|
5064
|
+
var isPathCollidingWithChipInterior = (path, chipObstacles) => {
|
|
5065
|
+
for (let i = 0; i < path.length - 1; i++) {
|
|
5066
|
+
const start = path[i];
|
|
5067
|
+
const end = path[i + 1];
|
|
5068
|
+
for (const obstacle of chipObstacles) {
|
|
5069
|
+
if (!segmentIntersectsRect(start, end, obstacle)) continue;
|
|
5070
|
+
if (segmentRunsAlongRectBoundary(start, end, obstacle)) continue;
|
|
5071
|
+
return true;
|
|
5072
|
+
}
|
|
5073
|
+
}
|
|
5074
|
+
return false;
|
|
5075
|
+
};
|
|
5076
|
+
|
|
5077
|
+
// lib/solvers/TraceCleanupSolver/sameNetRailAlignment/scoreRailAlignment.ts
|
|
5078
|
+
var countOtherNetCrossings = (traces, allTraces) => {
|
|
5079
|
+
let crossings = 0;
|
|
5080
|
+
for (const trace of traces) {
|
|
5081
|
+
for (const otherTrace of allTraces) {
|
|
5082
|
+
if (trace.globalConnNetId === otherTrace.globalConnNetId) continue;
|
|
5083
|
+
crossings += countPathIntersections(trace.tracePath, otherTrace.tracePath);
|
|
5084
|
+
}
|
|
5085
|
+
}
|
|
5086
|
+
return crossings;
|
|
5087
|
+
};
|
|
5088
|
+
var getTraceGeometryMetrics = (traces, allTraces) => ({
|
|
5089
|
+
turnCount: traces.reduce(
|
|
5090
|
+
(total, trace) => total + countTurns(trace.tracePath),
|
|
5091
|
+
0
|
|
5092
|
+
),
|
|
5093
|
+
visibleLength: getVisibleTraceLength(traces),
|
|
5094
|
+
pathLength: traces.reduce(
|
|
5095
|
+
(sum, trace) => sum + getPathLength(trace.tracePath),
|
|
5096
|
+
0
|
|
5097
|
+
),
|
|
5098
|
+
otherNetCrossings: countOtherNetCrossings(traces, allTraces)
|
|
5099
|
+
});
|
|
5100
|
+
var scoreIsBetter = (candidate, best) => {
|
|
5101
|
+
if (candidate.turnCount !== best.turnCount)
|
|
5102
|
+
return candidate.turnCount < best.turnCount;
|
|
5103
|
+
if (!nearlyEqual(candidate.visibleLength, best.visibleLength))
|
|
5104
|
+
return candidate.visibleLength < best.visibleLength;
|
|
5105
|
+
if (!nearlyEqual(candidate.pathLength, best.pathLength))
|
|
5106
|
+
return candidate.pathLength < best.pathLength;
|
|
5107
|
+
if (candidate.otherNetCrossings !== best.otherNetCrossings)
|
|
5108
|
+
return candidate.otherNetCrossings < best.otherNetCrossings;
|
|
5109
|
+
if (!nearlyEqual(candidate.displacement, best.displacement))
|
|
5110
|
+
return candidate.displacement < best.displacement;
|
|
5111
|
+
return candidate.coordinate < best.coordinate;
|
|
5112
|
+
};
|
|
5113
|
+
var isReadabilityImprovement = (candidate, baseline) => candidate.turnCount <= baseline.turnCount && (candidate.turnCount < baseline.turnCount || candidate.visibleLength <= baseline.visibleLength + RAIL_ALIGNMENT_EPSILON);
|
|
5114
|
+
|
|
5115
|
+
// lib/solvers/TraceCleanupSolver/sameNetRailAlignment/evaluateRailGroup.ts
|
|
5116
|
+
var tracePathChanged = (original, candidate) => original.tracePath.length !== candidate.tracePath.length || candidate.tracePath.some(
|
|
5117
|
+
(point, index) => !pointsEqual(point, original.tracePath[index])
|
|
5118
|
+
);
|
|
5119
|
+
var evaluateRailGroup = ({
|
|
5120
|
+
group,
|
|
5121
|
+
traces,
|
|
5122
|
+
netLabelPlacements,
|
|
5123
|
+
obstacles,
|
|
5124
|
+
eligibleTraceIds
|
|
5125
|
+
}) => {
|
|
5126
|
+
const groupTraceIds = new Set(group.map((segment) => segment.traceId));
|
|
5127
|
+
const originalGroupTraces = traces.filter(
|
|
5128
|
+
(trace) => groupTraceIds.has(trace.mspPairId)
|
|
5129
|
+
);
|
|
5130
|
+
const baseline = getTraceGeometryMetrics(originalGroupTraces, traces);
|
|
5131
|
+
const coordinates = getDistinctCoordinates(
|
|
5132
|
+
group.map((segment) => segment.coordinate)
|
|
5133
|
+
);
|
|
5134
|
+
const otherNetTraces = traces.filter(
|
|
5135
|
+
(trace) => trace.globalConnNetId !== group[0].globalConnNetId
|
|
5136
|
+
);
|
|
5137
|
+
const immutableSameNetTraces = traces.filter(
|
|
5138
|
+
(trace) => trace.globalConnNetId === group[0].globalConnNetId && !eligibleTraceIds.has(trace.mspPairId)
|
|
5139
|
+
);
|
|
5140
|
+
let best = null;
|
|
5141
|
+
for (const coordinate of coordinates) {
|
|
5142
|
+
const candidateMap = /* @__PURE__ */ new Map();
|
|
5143
|
+
for (const trace of originalGroupTraces) {
|
|
5144
|
+
const candidateTrace = moveRailSegments(
|
|
5145
|
+
trace,
|
|
5146
|
+
group.filter((segment) => segment.traceId === trace.mspPairId),
|
|
5147
|
+
coordinate
|
|
5148
|
+
);
|
|
5149
|
+
candidateMap.set(trace.mspPairId, candidateTrace);
|
|
5150
|
+
}
|
|
5151
|
+
const candidateTraces = [...candidateMap.values()];
|
|
5152
|
+
const allCandidateTraces = traces.map(
|
|
5153
|
+
(trace) => candidateMap.get(trace.mspPairId) ?? trace
|
|
5154
|
+
);
|
|
5155
|
+
const candidatesAreClear = candidateTraces.every(
|
|
5156
|
+
(candidate2) => !isPathCollidingWithObstacles(candidate2.tracePath, obstacles) && detectTraceLabelOverlap({
|
|
5157
|
+
traces: [candidate2],
|
|
5158
|
+
netLabels: netLabelPlacements
|
|
5159
|
+
}).length === 0 && !doesPathCoincideWithTraces(candidate2.tracePath, otherNetTraces) && !doesPathCoincideWithTraces(
|
|
5160
|
+
candidate2.tracePath,
|
|
5161
|
+
immutableSameNetTraces.filter(
|
|
5162
|
+
(trace) => trace.mspPairId !== candidate2.mspPairId
|
|
5163
|
+
)
|
|
5164
|
+
)
|
|
5165
|
+
);
|
|
5166
|
+
if (!candidatesAreClear) continue;
|
|
5167
|
+
if (!preservesLabelAnchors(netLabelPlacements, traces, allCandidateTraces)) {
|
|
5168
|
+
continue;
|
|
5169
|
+
}
|
|
5170
|
+
const metrics = getTraceGeometryMetrics(candidateTraces, allCandidateTraces);
|
|
5171
|
+
if (metrics.otherNetCrossings > baseline.otherNetCrossings) continue;
|
|
5172
|
+
if (!isReadabilityImprovement(metrics, baseline)) continue;
|
|
5173
|
+
const score = {
|
|
5174
|
+
...metrics,
|
|
5175
|
+
displacement: group.reduce(
|
|
5176
|
+
(sum, segment) => sum + Math.abs(segment.coordinate - coordinate),
|
|
5177
|
+
0
|
|
5178
|
+
),
|
|
5179
|
+
coordinate
|
|
5180
|
+
};
|
|
5181
|
+
const changedTraceIds = candidateTraces.filter((candidate2) => {
|
|
5182
|
+
const original = traces.find(
|
|
5183
|
+
(trace) => trace.mspPairId === candidate2.mspPairId
|
|
5184
|
+
);
|
|
5185
|
+
return tracePathChanged(original, candidate2);
|
|
5186
|
+
}).map((trace) => trace.mspPairId);
|
|
5187
|
+
if (changedTraceIds.length === 0) continue;
|
|
5188
|
+
const candidate = { traces: allCandidateTraces, changedTraceIds, score };
|
|
5189
|
+
if (!best || scoreIsBetter(candidate.score, best.score)) best = candidate;
|
|
5190
|
+
}
|
|
5191
|
+
return best;
|
|
5192
|
+
};
|
|
5193
|
+
|
|
5194
|
+
// lib/solvers/TraceCleanupSolver/sameNetRailAlignment/getComponentSideRailSegments.ts
|
|
5195
|
+
var getMovableRailSegments = (trace) => {
|
|
5196
|
+
const segments = [];
|
|
5197
|
+
const path = trace.tracePath;
|
|
5198
|
+
for (let segmentIndex = 1; segmentIndex < path.length - 2; segmentIndex++) {
|
|
5199
|
+
const previous = path[segmentIndex - 1];
|
|
5200
|
+
const start = path[segmentIndex];
|
|
5201
|
+
const end = path[segmentIndex + 1];
|
|
5202
|
+
const next = path[segmentIndex + 2];
|
|
5203
|
+
const orientation = getRailOrientation(start, end);
|
|
5204
|
+
if (!orientation) continue;
|
|
5205
|
+
const previousOrientation = getRailOrientation(previous, start);
|
|
5206
|
+
const nextOrientation = getRailOrientation(end, next);
|
|
5207
|
+
if (!previousOrientation || !nextOrientation) continue;
|
|
5208
|
+
if (previousOrientation === orientation || nextOrientation === orientation)
|
|
5209
|
+
continue;
|
|
5210
|
+
const alongValues = orientation === "vertical" ? [start.y, end.y] : [start.x, end.x];
|
|
5211
|
+
segments.push({
|
|
5212
|
+
traceId: trace.mspPairId,
|
|
5213
|
+
segmentIndex,
|
|
5214
|
+
globalConnNetId: trace.globalConnNetId,
|
|
5215
|
+
orientation,
|
|
5216
|
+
coordinate: orientation === "vertical" ? start.x : start.y,
|
|
5217
|
+
minAlong: Math.min(...alongValues),
|
|
5218
|
+
maxAlong: Math.max(...alongValues)
|
|
5219
|
+
});
|
|
5220
|
+
}
|
|
5221
|
+
return segments;
|
|
5222
|
+
};
|
|
5223
|
+
var railIsOutsideComponent = (segment, chip, facingDirection) => {
|
|
5224
|
+
const minX = chip.center.x - chip.width / 2;
|
|
5225
|
+
const maxX = chip.center.x + chip.width / 2;
|
|
5226
|
+
const minY = chip.center.y - chip.height / 2;
|
|
5227
|
+
const maxY = chip.center.y + chip.height / 2;
|
|
5228
|
+
switch (facingDirection) {
|
|
5229
|
+
case "x-":
|
|
5230
|
+
return segment.orientation === "vertical" && segment.coordinate <= minX + RAIL_ALIGNMENT_EPSILON;
|
|
5231
|
+
case "x+":
|
|
5232
|
+
return segment.orientation === "vertical" && segment.coordinate >= maxX - RAIL_ALIGNMENT_EPSILON;
|
|
5233
|
+
case "y+":
|
|
5234
|
+
return segment.orientation === "horizontal" && segment.coordinate >= maxY - RAIL_ALIGNMENT_EPSILON;
|
|
5235
|
+
case "y-":
|
|
5236
|
+
return segment.orientation === "horizontal" && segment.coordinate <= minY + RAIL_ALIGNMENT_EPSILON;
|
|
5237
|
+
}
|
|
5238
|
+
};
|
|
5239
|
+
var getComponentSideRailSegments = (trace, chipMap) => {
|
|
5240
|
+
const segments = [];
|
|
5241
|
+
for (const segment of getMovableRailSegments(trace)) {
|
|
5242
|
+
const associations = trace.pins.flatMap((pin, pinIndex) => {
|
|
5243
|
+
const chip = chipMap.get(pin.chipId);
|
|
5244
|
+
if (!chip) return [];
|
|
5245
|
+
const componentFacingDirection = pin._facingDirection ?? getPinDirection(pin, chip);
|
|
5246
|
+
if (!railIsOutsideComponent(segment, chip, componentFacingDirection)) {
|
|
5247
|
+
return [];
|
|
5248
|
+
}
|
|
5249
|
+
return [
|
|
5250
|
+
{
|
|
5251
|
+
componentId: chip.chipId,
|
|
5252
|
+
componentFacingDirection,
|
|
5253
|
+
distanceFromEndpoint: pinIndex === 0 ? segment.segmentIndex : trace.tracePath.length - 2 - segment.segmentIndex
|
|
5254
|
+
}
|
|
5255
|
+
];
|
|
5256
|
+
});
|
|
5257
|
+
associations.sort((a, b) => a.distanceFromEndpoint - b.distanceFromEndpoint);
|
|
5258
|
+
const association = associations[0];
|
|
5259
|
+
if (!association) continue;
|
|
5260
|
+
segments.push({ ...segment, ...association });
|
|
5261
|
+
}
|
|
5262
|
+
return segments;
|
|
5263
|
+
};
|
|
5264
|
+
|
|
5265
|
+
// lib/solvers/TraceCleanupSolver/sameNetRailAlignment/getRailGroups.ts
|
|
5266
|
+
var getCorridor = (a, b) => {
|
|
5267
|
+
const overlapMin = Math.max(a.minAlong, b.minAlong);
|
|
5268
|
+
const overlapMax = Math.min(a.maxAlong, b.maxAlong);
|
|
5269
|
+
const along = (overlapMin + overlapMax) / 2;
|
|
5270
|
+
return a.orientation === "vertical" ? [
|
|
5271
|
+
{ x: a.coordinate, y: along },
|
|
5272
|
+
{ x: b.coordinate, y: along }
|
|
5273
|
+
] : [
|
|
5274
|
+
{ x: along, y: a.coordinate },
|
|
5275
|
+
{ x: along, y: b.coordinate }
|
|
5276
|
+
];
|
|
5277
|
+
};
|
|
5278
|
+
var corridorIsClear = (a, b, obstacles) => {
|
|
5279
|
+
if (!rangesTouchOrOverlap(a, b)) return true;
|
|
5280
|
+
const [start, end] = getCorridor(a, b);
|
|
5281
|
+
return !obstacles.some(
|
|
5282
|
+
(obstacle) => segmentIntersectsRect(start, end, obstacle)
|
|
5283
|
+
);
|
|
5284
|
+
};
|
|
5285
|
+
var tracesSharePin = (a, b, traceMap) => {
|
|
5286
|
+
if (a.traceId === b.traceId) return true;
|
|
5287
|
+
const aPinIds = new Set(traceMap.get(a.traceId).pins.map((pin) => pin.pinId));
|
|
5288
|
+
return traceMap.get(b.traceId).pins.some((pin) => aPinIds.has(pin.pinId));
|
|
5289
|
+
};
|
|
5290
|
+
var canJoinRailGroup = (start, current, candidate, traceMap, obstacles) => candidate.globalConnNetId === start.globalConnNetId && candidate.orientation === start.orientation && candidate.componentId === start.componentId && candidate.componentFacingDirection === start.componentFacingDirection && (rangesTouchOrOverlap(current, candidate) || tracesSharePin(current, candidate, traceMap)) && corridorIsClear(current, candidate, obstacles);
|
|
5291
|
+
var getRailGroups = (traces, eligibleTraceIds, inputProblem, obstacles) => {
|
|
5292
|
+
const chipMap = new Map(inputProblem.chips.map((chip) => [chip.chipId, chip]));
|
|
5293
|
+
const segments = traces.filter((trace) => eligibleTraceIds.has(trace.mspPairId)).flatMap((trace) => getComponentSideRailSegments(trace, chipMap));
|
|
5294
|
+
const traceMap = new Map(traces.map((trace) => [trace.mspPairId, trace]));
|
|
5295
|
+
const visited = /* @__PURE__ */ new Set();
|
|
5296
|
+
const groups = [];
|
|
5297
|
+
for (let startIndex = 0; startIndex < segments.length; startIndex++) {
|
|
5298
|
+
if (visited.has(startIndex)) continue;
|
|
5299
|
+
const start = segments[startIndex];
|
|
5300
|
+
const queue = [startIndex];
|
|
5301
|
+
const group = [];
|
|
5302
|
+
visited.add(startIndex);
|
|
5303
|
+
for (let queueIndex = 0; queueIndex < queue.length; queueIndex++) {
|
|
5304
|
+
const current = segments[queue[queueIndex]];
|
|
5305
|
+
group.push(current);
|
|
5306
|
+
for (let candidateIndex = 0; candidateIndex < segments.length; candidateIndex++) {
|
|
5307
|
+
if (visited.has(candidateIndex)) continue;
|
|
5308
|
+
const candidate = segments[candidateIndex];
|
|
5309
|
+
if (!canJoinRailGroup(start, current, candidate, traceMap, obstacles)) {
|
|
5310
|
+
continue;
|
|
5311
|
+
}
|
|
5312
|
+
visited.add(candidateIndex);
|
|
5313
|
+
queue.push(candidateIndex);
|
|
5314
|
+
}
|
|
5315
|
+
}
|
|
5316
|
+
const traceCount = new Set(group.map((segment) => segment.traceId)).size;
|
|
5317
|
+
const hasDifferentCoordinates = group.some(
|
|
5318
|
+
(segment) => !nearlyEqual(segment.coordinate, group[0].coordinate)
|
|
5319
|
+
);
|
|
5320
|
+
if (traceCount >= 2 && hasDifferentCoordinates) groups.push(group);
|
|
5321
|
+
}
|
|
5322
|
+
return groups;
|
|
5323
|
+
};
|
|
5324
|
+
|
|
5325
|
+
// lib/solvers/TraceCleanupSolver/alignSameNetRails.ts
|
|
5326
|
+
var alignSameNetRails = ({
|
|
5327
|
+
inputProblem,
|
|
5328
|
+
traces,
|
|
5329
|
+
netLabelPlacements,
|
|
5330
|
+
eligibleTraceIds
|
|
5331
|
+
}) => {
|
|
5332
|
+
let outputTraces = [...traces];
|
|
5333
|
+
const obstacles = getObstacleRects(inputProblem);
|
|
5334
|
+
const alignedTraceIds = /* @__PURE__ */ new Set();
|
|
5335
|
+
let alignedRailGroupCount = 0;
|
|
5336
|
+
const maximumPasses = Math.max(
|
|
5337
|
+
1,
|
|
5338
|
+
traces.reduce((sum, trace) => sum + trace.tracePath.length, 0)
|
|
5339
|
+
);
|
|
5340
|
+
for (let pass = 0; pass < maximumPasses; pass++) {
|
|
5341
|
+
const groups = getRailGroups(
|
|
5342
|
+
outputTraces,
|
|
5343
|
+
eligibleTraceIds,
|
|
5344
|
+
inputProblem,
|
|
5345
|
+
obstacles
|
|
5346
|
+
);
|
|
5347
|
+
let applied = null;
|
|
5348
|
+
for (const group of groups) {
|
|
5349
|
+
applied = evaluateRailGroup({
|
|
5350
|
+
group,
|
|
5351
|
+
traces: outputTraces,
|
|
5352
|
+
netLabelPlacements,
|
|
5353
|
+
obstacles,
|
|
5354
|
+
eligibleTraceIds
|
|
5355
|
+
});
|
|
5356
|
+
if (applied) break;
|
|
4685
5357
|
}
|
|
5358
|
+
if (!applied) break;
|
|
5359
|
+
outputTraces = applied.traces;
|
|
5360
|
+
alignedRailGroupCount++;
|
|
5361
|
+
for (const traceId of applied.changedTraceIds) alignedTraceIds.add(traceId);
|
|
4686
5362
|
}
|
|
4687
|
-
const finalSimplifiedPath = simplifyPath(newPath);
|
|
4688
5363
|
return {
|
|
4689
|
-
|
|
4690
|
-
|
|
5364
|
+
traces: outputTraces,
|
|
5365
|
+
alignedRailGroupCount,
|
|
5366
|
+
alignedTraceCount: alignedTraceIds.size
|
|
4691
5367
|
};
|
|
4692
5368
|
};
|
|
4693
5369
|
|
|
@@ -4748,8 +5424,8 @@ var findIntersectionsWithObstacles = (p1, p2, obstacles) => {
|
|
|
4748
5424
|
};
|
|
4749
5425
|
|
|
4750
5426
|
// lib/solvers/TraceCleanupSolver/sub-solver/generateLShapeRerouteCandidates.ts
|
|
4751
|
-
var
|
|
4752
|
-
var
|
|
5427
|
+
var EPS7 = 1e-6;
|
|
5428
|
+
var isVertical3 = (a, b, eps = EPS7) => Math.abs(a.x - b.x) < eps;
|
|
4753
5429
|
var generateLShapeRerouteCandidates = ({
|
|
4754
5430
|
lShape,
|
|
4755
5431
|
rectangle,
|
|
@@ -4762,50 +5438,50 @@ var generateLShapeRerouteCandidates = ({
|
|
|
4762
5438
|
let c2;
|
|
4763
5439
|
let i1_padded = interactionPoint1;
|
|
4764
5440
|
let i2_padded = interactionPoint2;
|
|
4765
|
-
if (Math.abs(p2.x - x) <
|
|
5441
|
+
if (Math.abs(p2.x - x) < EPS7 && Math.abs(p2.y - (y + height)) < EPS7) {
|
|
4766
5442
|
c2 = { x: x + width + padding, y: y - padding };
|
|
4767
|
-
if (
|
|
5443
|
+
if (isVertical3(p1, p2)) {
|
|
4768
5444
|
i1_padded = { x: interactionPoint1.x, y: interactionPoint1.y - padding };
|
|
4769
5445
|
} else {
|
|
4770
5446
|
i1_padded = { x: interactionPoint1.x + padding, y: interactionPoint1.y };
|
|
4771
5447
|
}
|
|
4772
|
-
if (
|
|
5448
|
+
if (isVertical3(p2, p3)) {
|
|
4773
5449
|
i2_padded = { x: interactionPoint2.x, y: interactionPoint2.y - padding };
|
|
4774
5450
|
} else {
|
|
4775
5451
|
i2_padded = { x: interactionPoint2.x + padding, y: interactionPoint2.y };
|
|
4776
5452
|
}
|
|
4777
|
-
} else if (Math.abs(p2.x - (x + width)) <
|
|
5453
|
+
} else if (Math.abs(p2.x - (x + width)) < EPS7 && Math.abs(p2.y - (y + height)) < EPS7) {
|
|
4778
5454
|
c2 = { x: x - padding, y: y - padding };
|
|
4779
|
-
if (
|
|
5455
|
+
if (isVertical3(p1, p2)) {
|
|
4780
5456
|
i1_padded = { x: interactionPoint1.x, y: interactionPoint1.y - padding };
|
|
4781
5457
|
} else {
|
|
4782
5458
|
i1_padded = { x: interactionPoint1.x - padding, y: interactionPoint1.y };
|
|
4783
5459
|
}
|
|
4784
|
-
if (
|
|
5460
|
+
if (isVertical3(p2, p3)) {
|
|
4785
5461
|
i2_padded = { x: interactionPoint2.x, y: interactionPoint2.y - padding };
|
|
4786
5462
|
} else {
|
|
4787
5463
|
i2_padded = { x: interactionPoint2.x - padding, y: interactionPoint2.y };
|
|
4788
5464
|
}
|
|
4789
|
-
} else if (Math.abs(p2.x - x) <
|
|
5465
|
+
} else if (Math.abs(p2.x - x) < EPS7 && Math.abs(p2.y - y) < EPS7) {
|
|
4790
5466
|
c2 = { x: x + width + padding, y: y + height + padding };
|
|
4791
|
-
if (
|
|
5467
|
+
if (isVertical3(p1, p2)) {
|
|
4792
5468
|
i1_padded = { x: interactionPoint1.x, y: interactionPoint1.y + padding };
|
|
4793
5469
|
} else {
|
|
4794
5470
|
i1_padded = { x: interactionPoint1.x + padding, y: interactionPoint1.y };
|
|
4795
5471
|
}
|
|
4796
|
-
if (
|
|
5472
|
+
if (isVertical3(p2, p3)) {
|
|
4797
5473
|
i2_padded = { x: interactionPoint2.x, y: interactionPoint2.y + padding };
|
|
4798
5474
|
} else {
|
|
4799
5475
|
i2_padded = { x: interactionPoint2.x + padding, y: interactionPoint2.y };
|
|
4800
5476
|
}
|
|
4801
|
-
} else if (Math.abs(p2.x - (x + width)) <
|
|
5477
|
+
} else if (Math.abs(p2.x - (x + width)) < EPS7 && Math.abs(p2.y - y) < EPS7) {
|
|
4802
5478
|
c2 = { x: x - padding, y: y + height + padding };
|
|
4803
|
-
if (
|
|
5479
|
+
if (isVertical3(p1, p2)) {
|
|
4804
5480
|
i1_padded = { x: interactionPoint1.x, y: interactionPoint1.y + padding };
|
|
4805
5481
|
} else {
|
|
4806
5482
|
i1_padded = { x: interactionPoint1.x - padding, y: interactionPoint1.y };
|
|
4807
5483
|
}
|
|
4808
|
-
if (
|
|
5484
|
+
if (isVertical3(p2, p3)) {
|
|
4809
5485
|
i2_padded = { x: interactionPoint2.x, y: interactionPoint2.y + padding };
|
|
4810
5486
|
} else {
|
|
4811
5487
|
i2_padded = { x: interactionPoint2.x - padding, y: interactionPoint2.y };
|
|
@@ -5269,9 +5945,9 @@ var UntangleTraceSubsolver = class extends BaseSolver {
|
|
|
5269
5945
|
};
|
|
5270
5946
|
|
|
5271
5947
|
// lib/solvers/TraceCleanupSolver/is4PointRectangle.ts
|
|
5272
|
-
var
|
|
5273
|
-
var sameX = (a, b) => Math.abs(a.x - b.x) <=
|
|
5274
|
-
var sameY = (a, b) => Math.abs(a.y - b.y) <=
|
|
5948
|
+
var EPS8 = 1e-6;
|
|
5949
|
+
var sameX = (a, b) => Math.abs(a.x - b.x) <= EPS8;
|
|
5950
|
+
var sameY = (a, b) => Math.abs(a.y - b.y) <= EPS8;
|
|
5275
5951
|
var is4PointRectangle = (path) => {
|
|
5276
5952
|
if (path.length !== 4) return false;
|
|
5277
5953
|
const [p0, p1, p2, p3] = path;
|
|
@@ -5281,12 +5957,19 @@ var is4PointRectangle = (path) => {
|
|
|
5281
5957
|
};
|
|
5282
5958
|
|
|
5283
5959
|
// lib/solvers/TraceCleanupSolver/TraceCleanupSolver.ts
|
|
5960
|
+
var DEFAULT_OPERATIONS = [
|
|
5961
|
+
"untangling_traces",
|
|
5962
|
+
"minimizing_turns",
|
|
5963
|
+
"balancing_l_shapes"
|
|
5964
|
+
];
|
|
5284
5965
|
var TraceCleanupSolver = class extends BaseSolver {
|
|
5285
5966
|
input;
|
|
5286
5967
|
outputTraces;
|
|
5287
5968
|
traceIdQueue;
|
|
5288
5969
|
tracesMap;
|
|
5289
|
-
|
|
5970
|
+
operations;
|
|
5971
|
+
operationIndex = 0;
|
|
5972
|
+
pipelineStep;
|
|
5290
5973
|
activeTraceId = null;
|
|
5291
5974
|
// New property
|
|
5292
5975
|
activeSubSolver = null;
|
|
@@ -5295,6 +5978,8 @@ var TraceCleanupSolver = class extends BaseSolver {
|
|
|
5295
5978
|
this.input = solverInput;
|
|
5296
5979
|
this.outputTraces = [...solverInput.allTraces];
|
|
5297
5980
|
this.tracesMap = new Map(this.outputTraces.map((t) => [t.mspPairId, t]));
|
|
5981
|
+
this.operations = solverInput.operations ?? DEFAULT_OPERATIONS;
|
|
5982
|
+
this.pipelineStep = this.operations[0] ?? null;
|
|
5298
5983
|
this.traceIdQueue = Array.from(
|
|
5299
5984
|
solverInput.allTraces.map((e) => e.mspPairId)
|
|
5300
5985
|
);
|
|
@@ -5307,13 +5992,17 @@ var TraceCleanupSolver = class extends BaseSolver {
|
|
|
5307
5992
|
this.outputTraces = output.traces;
|
|
5308
5993
|
this.tracesMap = new Map(this.outputTraces.map((t) => [t.mspPairId, t]));
|
|
5309
5994
|
this.activeSubSolver = null;
|
|
5310
|
-
this.
|
|
5995
|
+
this._advancePipeline();
|
|
5311
5996
|
} else if (this.activeSubSolver.failed) {
|
|
5312
5997
|
this.activeSubSolver = null;
|
|
5313
|
-
this.
|
|
5998
|
+
this._advancePipeline();
|
|
5314
5999
|
}
|
|
5315
6000
|
return;
|
|
5316
6001
|
}
|
|
6002
|
+
if (!this.pipelineStep) {
|
|
6003
|
+
this.solved = true;
|
|
6004
|
+
return;
|
|
6005
|
+
}
|
|
5317
6006
|
switch (this.pipelineStep) {
|
|
5318
6007
|
case "untangling_traces":
|
|
5319
6008
|
this._runUntangleTracesStep();
|
|
@@ -5324,8 +6013,17 @@ var TraceCleanupSolver = class extends BaseSolver {
|
|
|
5324
6013
|
case "balancing_l_shapes":
|
|
5325
6014
|
this._runBalanceLShapesStep();
|
|
5326
6015
|
break;
|
|
6016
|
+
case "aligning_same_net_rails":
|
|
6017
|
+
this._runAlignSameNetRailsStep();
|
|
6018
|
+
break;
|
|
5327
6019
|
}
|
|
5328
6020
|
}
|
|
6021
|
+
_advancePipeline() {
|
|
6022
|
+
this.operationIndex++;
|
|
6023
|
+
this.pipelineStep = this.operations[this.operationIndex] ?? null;
|
|
6024
|
+
this.traceIdQueue = this.outputTraces.map((trace) => trace.mspPairId);
|
|
6025
|
+
if (this.pipelineStep) this.activeTraceId = null;
|
|
6026
|
+
}
|
|
5329
6027
|
_runUntangleTracesStep() {
|
|
5330
6028
|
this.activeSubSolver = new UntangleTraceSubsolver({
|
|
5331
6029
|
...this.input,
|
|
@@ -5334,17 +6032,14 @@ var TraceCleanupSolver = class extends BaseSolver {
|
|
|
5334
6032
|
}
|
|
5335
6033
|
_runMinimizeTurnsStep() {
|
|
5336
6034
|
if (this.traceIdQueue.length === 0) {
|
|
5337
|
-
this.
|
|
5338
|
-
this.traceIdQueue = Array.from(
|
|
5339
|
-
this.input.allTraces.map((e) => e.mspPairId)
|
|
5340
|
-
);
|
|
6035
|
+
this._advancePipeline();
|
|
5341
6036
|
return;
|
|
5342
6037
|
}
|
|
5343
6038
|
this._processTrace("minimizing_turns");
|
|
5344
6039
|
}
|
|
5345
6040
|
_runBalanceLShapesStep() {
|
|
5346
6041
|
if (this.traceIdQueue.length === 0) {
|
|
5347
|
-
this.
|
|
6042
|
+
this._advancePipeline();
|
|
5348
6043
|
return;
|
|
5349
6044
|
}
|
|
5350
6045
|
this._processTrace("balancing_l_shapes");
|
|
@@ -5374,6 +6069,19 @@ var TraceCleanupSolver = class extends BaseSolver {
|
|
|
5374
6069
|
this.tracesMap.set(targetMspConnectionPairId, updatedTrace);
|
|
5375
6070
|
this.outputTraces = Array.from(this.tracesMap.values());
|
|
5376
6071
|
}
|
|
6072
|
+
_runAlignSameNetRailsStep() {
|
|
6073
|
+
const alignment = alignSameNetRails({
|
|
6074
|
+
inputProblem: this.input.inputProblem,
|
|
6075
|
+
traces: this.outputTraces,
|
|
6076
|
+
netLabelPlacements: this.input.allLabelPlacements,
|
|
6077
|
+
eligibleTraceIds: this.input.eligibleTraceIds ?? new Set(this.outputTraces.map((trace) => trace.mspPairId))
|
|
6078
|
+
});
|
|
6079
|
+
this.outputTraces = alignment.traces;
|
|
6080
|
+
this.tracesMap = new Map(this.outputTraces.map((t) => [t.mspPairId, t]));
|
|
6081
|
+
this.stats.alignedRailGroupCount = alignment.alignedRailGroupCount;
|
|
6082
|
+
this.stats.alignedTraceCount = alignment.alignedTraceCount;
|
|
6083
|
+
this._advancePipeline();
|
|
6084
|
+
}
|
|
5377
6085
|
getOutput() {
|
|
5378
6086
|
return {
|
|
5379
6087
|
traces: this.outputTraces
|
|
@@ -5452,160 +6160,6 @@ var dir = (facingDirection) => {
|
|
|
5452
6160
|
throw new Error(`Invalid facing direction: ${facingDirection}`);
|
|
5453
6161
|
};
|
|
5454
6162
|
|
|
5455
|
-
// lib/solvers/Example28Solver/types.ts
|
|
5456
|
-
var EPS7 = 1e-9;
|
|
5457
|
-
|
|
5458
|
-
// lib/solvers/Example28Solver/segmentRunsAlongRectBoundary.ts
|
|
5459
|
-
var segmentRunsAlongRectBoundary = (start, end, rect) => {
|
|
5460
|
-
const isVertical4 = Math.abs(start.x - end.x) < EPS7;
|
|
5461
|
-
const isHorizontal3 = Math.abs(start.y - end.y) < EPS7;
|
|
5462
|
-
if (isVertical4) {
|
|
5463
|
-
return Math.abs(start.x - rect.minX) < EPS7 || Math.abs(start.x - rect.maxX) < EPS7;
|
|
5464
|
-
}
|
|
5465
|
-
if (isHorizontal3) {
|
|
5466
|
-
return Math.abs(start.y - rect.minY) < EPS7 || Math.abs(start.y - rect.maxY) < EPS7;
|
|
5467
|
-
}
|
|
5468
|
-
return false;
|
|
5469
|
-
};
|
|
5470
|
-
|
|
5471
|
-
// lib/solvers/Example28Solver/geometry.ts
|
|
5472
|
-
var getPathKey = (path) => path.map((point) => `${point.x},${point.y}`).join(";");
|
|
5473
|
-
var getPathLength = (path) => {
|
|
5474
|
-
let length = 0;
|
|
5475
|
-
for (let i = 0; i < path.length - 1; i++) {
|
|
5476
|
-
length += Math.abs(path[i + 1].x - path[i].x) + Math.abs(path[i + 1].y - path[i].y);
|
|
5477
|
-
}
|
|
5478
|
-
return length;
|
|
5479
|
-
};
|
|
5480
|
-
var getDistance = (a, b) => Math.abs(a.x - b.x) + Math.abs(a.y - b.y);
|
|
5481
|
-
var isAxisAlignedSegment = (start, end) => Math.abs(start.x - end.x) < EPS7 || Math.abs(start.y - end.y) < EPS7;
|
|
5482
|
-
var getSegmentOrientation = (start, end) => Math.abs(start.y - end.y) < EPS7 ? "horizontal" : "vertical";
|
|
5483
|
-
var projectPointToSegment = (point, start, end) => {
|
|
5484
|
-
if (Math.abs(start.x - end.x) < EPS7) {
|
|
5485
|
-
return {
|
|
5486
|
-
x: start.x,
|
|
5487
|
-
y: Math.min(
|
|
5488
|
-
Math.max(point.y, Math.min(start.y, end.y)),
|
|
5489
|
-
Math.max(start.y, end.y)
|
|
5490
|
-
)
|
|
5491
|
-
};
|
|
5492
|
-
}
|
|
5493
|
-
if (Math.abs(start.y - end.y) < EPS7) {
|
|
5494
|
-
return {
|
|
5495
|
-
x: Math.min(
|
|
5496
|
-
Math.max(point.x, Math.min(start.x, end.x)),
|
|
5497
|
-
Math.max(start.x, end.x)
|
|
5498
|
-
),
|
|
5499
|
-
y: start.y
|
|
5500
|
-
};
|
|
5501
|
-
}
|
|
5502
|
-
return start;
|
|
5503
|
-
};
|
|
5504
|
-
var getPointToSegmentDistance = (point, start, end) => getDistance(point, projectPointToSegment(point, start, end));
|
|
5505
|
-
var getSegments = (path) => {
|
|
5506
|
-
const segments = [];
|
|
5507
|
-
for (let i = 0; i < path.length - 1; i++) {
|
|
5508
|
-
const start = path[i];
|
|
5509
|
-
const end = path[i + 1];
|
|
5510
|
-
if (!isAxisAlignedSegment(start, end)) continue;
|
|
5511
|
-
segments.push({
|
|
5512
|
-
start,
|
|
5513
|
-
end,
|
|
5514
|
-
orientation: getSegmentOrientation(start, end)
|
|
5515
|
-
});
|
|
5516
|
-
}
|
|
5517
|
-
return segments;
|
|
5518
|
-
};
|
|
5519
|
-
var findSegmentContainingPoint = (path, point) => {
|
|
5520
|
-
for (let i = 0; i < path.length - 1; i++) {
|
|
5521
|
-
const start = path[i];
|
|
5522
|
-
const end = path[i + 1];
|
|
5523
|
-
if (!isAxisAlignedSegment(start, end)) continue;
|
|
5524
|
-
if (getPointToSegmentDistance(point, start, end) > 1e-6) continue;
|
|
5525
|
-
return {
|
|
5526
|
-
index: i,
|
|
5527
|
-
start,
|
|
5528
|
-
end,
|
|
5529
|
-
orientation: getSegmentOrientation(start, end)
|
|
5530
|
-
};
|
|
5531
|
-
}
|
|
5532
|
-
return null;
|
|
5533
|
-
};
|
|
5534
|
-
var isPointWithinSegmentPrimaryRange = (point, segment) => {
|
|
5535
|
-
if (segment.orientation === "horizontal") {
|
|
5536
|
-
return point.x >= Math.min(segment.start.x, segment.end.x) - EPS7 && point.x <= Math.max(segment.start.x, segment.end.x) + EPS7;
|
|
5537
|
-
}
|
|
5538
|
-
return point.y >= Math.min(segment.start.y, segment.end.y) - EPS7 && point.y <= Math.max(segment.start.y, segment.end.y) + EPS7;
|
|
5539
|
-
};
|
|
5540
|
-
var findPreferredReroutedSegment = (path, originalSegmentIndex, originalSegmentCount, orientation, anchorPoint) => {
|
|
5541
|
-
const matchingSegments = getSegments(path).filter(
|
|
5542
|
-
(segment) => segment.orientation === orientation
|
|
5543
|
-
);
|
|
5544
|
-
if (matchingSegments.length === 0) return null;
|
|
5545
|
-
const containingSegments = matchingSegments.filter(
|
|
5546
|
-
(segment) => isPointWithinSegmentPrimaryRange(anchorPoint, segment)
|
|
5547
|
-
);
|
|
5548
|
-
const candidateSegments = containingSegments.length > 0 ? containingSegments : matchingSegments;
|
|
5549
|
-
const isNearStart = originalSegmentIndex < originalSegmentCount / 2;
|
|
5550
|
-
return isNearStart ? candidateSegments[0] : candidateSegments[candidateSegments.length - 1];
|
|
5551
|
-
};
|
|
5552
|
-
var projectPointToPath = (point, path) => {
|
|
5553
|
-
let bestPoint = null;
|
|
5554
|
-
let bestDistance = Number.POSITIVE_INFINITY;
|
|
5555
|
-
for (let i = 0; i < path.length - 1; i++) {
|
|
5556
|
-
const projectedPoint = projectPointToSegment(point, path[i], path[i + 1]);
|
|
5557
|
-
const distance3 = getDistance(point, projectedPoint);
|
|
5558
|
-
if (distance3 < bestDistance) {
|
|
5559
|
-
bestPoint = projectedPoint;
|
|
5560
|
-
bestDistance = distance3;
|
|
5561
|
-
}
|
|
5562
|
-
}
|
|
5563
|
-
return bestPoint;
|
|
5564
|
-
};
|
|
5565
|
-
var segmentsIntersect = (a1, a2, b1, b2) => {
|
|
5566
|
-
const aVertical = Math.abs(a1.x - a2.x) < EPS7;
|
|
5567
|
-
const bVertical = Math.abs(b1.x - b2.x) < EPS7;
|
|
5568
|
-
const between = (value, p1, p2) => value >= Math.min(p1, p2) - EPS7 && value <= Math.max(p1, p2) + EPS7;
|
|
5569
|
-
if (aVertical && bVertical) {
|
|
5570
|
-
if (Math.abs(a1.x - b1.x) > EPS7) return false;
|
|
5571
|
-
const overlap = Math.min(Math.max(a1.y, a2.y), Math.max(b1.y, b2.y)) - Math.max(Math.min(a1.y, a2.y), Math.min(b1.y, b2.y));
|
|
5572
|
-
return overlap > EPS7;
|
|
5573
|
-
}
|
|
5574
|
-
if (!aVertical && !bVertical) {
|
|
5575
|
-
if (Math.abs(a1.y - b1.y) > EPS7) return false;
|
|
5576
|
-
const overlap = Math.min(Math.max(a1.x, a2.x), Math.max(b1.x, b2.x)) - Math.max(Math.min(a1.x, a2.x), Math.min(b1.x, b2.x));
|
|
5577
|
-
return overlap > EPS7;
|
|
5578
|
-
}
|
|
5579
|
-
const verticalA = aVertical ? a1 : b1;
|
|
5580
|
-
const verticalB = aVertical ? a2 : b2;
|
|
5581
|
-
const horizontalA = aVertical ? b1 : a1;
|
|
5582
|
-
const horizontalB = aVertical ? b2 : a2;
|
|
5583
|
-
return between(verticalA.x, horizontalA.x, horizontalB.x) && between(horizontalA.y, verticalA.y, verticalB.y);
|
|
5584
|
-
};
|
|
5585
|
-
var countPathIntersections = (pathA, pathB) => {
|
|
5586
|
-
let count = 0;
|
|
5587
|
-
for (let i = 0; i < pathA.length - 1; i++) {
|
|
5588
|
-
for (let j = 0; j < pathB.length - 1; j++) {
|
|
5589
|
-
if (segmentsIntersect(pathA[i], pathA[i + 1], pathB[j], pathB[j + 1])) {
|
|
5590
|
-
count++;
|
|
5591
|
-
}
|
|
5592
|
-
}
|
|
5593
|
-
}
|
|
5594
|
-
return count;
|
|
5595
|
-
};
|
|
5596
|
-
var isPathCollidingWithChipInterior = (path, chipObstacles) => {
|
|
5597
|
-
for (let i = 0; i < path.length - 1; i++) {
|
|
5598
|
-
const start = path[i];
|
|
5599
|
-
const end = path[i + 1];
|
|
5600
|
-
for (const obstacle of chipObstacles) {
|
|
5601
|
-
if (!segmentIntersectsRect(start, end, obstacle)) continue;
|
|
5602
|
-
if (segmentRunsAlongRectBoundary(start, end, obstacle)) continue;
|
|
5603
|
-
return true;
|
|
5604
|
-
}
|
|
5605
|
-
}
|
|
5606
|
-
return false;
|
|
5607
|
-
};
|
|
5608
|
-
|
|
5609
6163
|
// lib/solvers/Example28Solver/getMovedAnchorPointForReroute.ts
|
|
5610
6164
|
var getMovedAnchorPointForReroute = (anchorPoint, originalTracePath, reroutedTracePath) => {
|
|
5611
6165
|
const originalSegment = findSegmentContainingPoint(
|
|
@@ -5668,7 +6222,7 @@ var doesPathRunAlongChipBoundary = (path, chipObstacles) => {
|
|
|
5668
6222
|
const end = path[i + 1];
|
|
5669
6223
|
for (const obstacle of chipObstacles) {
|
|
5670
6224
|
if (!segmentRunsAlongRectBoundary(start, end, obstacle)) continue;
|
|
5671
|
-
if (getSegmentOverlapWithRectSpan(start, end, obstacle) >
|
|
6225
|
+
if (getSegmentOverlapWithRectSpan(start, end, obstacle) > EPS6) {
|
|
5672
6226
|
return true;
|
|
5673
6227
|
}
|
|
5674
6228
|
}
|
|
@@ -5683,14 +6237,14 @@ var getChipBoundaryOverlap = (path, chipObstacles) => {
|
|
|
5683
6237
|
for (const obstacle of chipObstacles) {
|
|
5684
6238
|
if (!segmentRunsAlongRectBoundary(start, end, obstacle)) continue;
|
|
5685
6239
|
const overlap = getSegmentOverlapWithRectSpan(start, end, obstacle);
|
|
5686
|
-
if (overlap >
|
|
6240
|
+
if (overlap > EPS6) total += overlap;
|
|
5687
6241
|
}
|
|
5688
6242
|
}
|
|
5689
6243
|
return total;
|
|
5690
6244
|
};
|
|
5691
6245
|
var getSegmentOverlapWithRectSpan = (start, end, rect) => {
|
|
5692
|
-
const
|
|
5693
|
-
if (
|
|
6246
|
+
const isVertical5 = Math.abs(start.x - end.x) < EPS6;
|
|
6247
|
+
if (isVertical5) {
|
|
5694
6248
|
return Math.min(Math.max(start.y, end.y), rect.maxY) - Math.max(Math.min(start.y, end.y), rect.minY);
|
|
5695
6249
|
}
|
|
5696
6250
|
return Math.min(Math.max(start.x, end.x), rect.maxX) - Math.max(Math.min(start.x, end.x), rect.minX);
|
|
@@ -6101,11 +6655,11 @@ var getLabelHugDistance = (tracePath, obstacleLabel) => {
|
|
|
6101
6655
|
obstacleLabel.width,
|
|
6102
6656
|
obstacleLabel.height
|
|
6103
6657
|
);
|
|
6104
|
-
let
|
|
6658
|
+
let distance4 = 0;
|
|
6105
6659
|
for (const point of tracePath) {
|
|
6106
|
-
|
|
6660
|
+
distance4 += getPointDistanceFromRect(point, bounds);
|
|
6107
6661
|
}
|
|
6108
|
-
return
|
|
6662
|
+
return distance4;
|
|
6109
6663
|
};
|
|
6110
6664
|
var getPointDistanceFromRect = (point, rect) => {
|
|
6111
6665
|
const dx = Math.max(rect.minX - point.x, 0, point.x - rect.maxX);
|
|
@@ -6382,16 +6936,16 @@ var Example28Solver = class extends BaseSolver {
|
|
|
6382
6936
|
const outward = dir(label.orientation);
|
|
6383
6937
|
if (outward.x === 0 && outward.y === 0) return null;
|
|
6384
6938
|
for (let step = 1; step <= LABEL_MAX_OUTWARD_STEPS; step++) {
|
|
6385
|
-
const
|
|
6939
|
+
const distance4 = step * LABEL_OUTWARD_STEP;
|
|
6386
6940
|
const candidate = {
|
|
6387
6941
|
...label,
|
|
6388
6942
|
anchorPoint: {
|
|
6389
|
-
x: label.anchorPoint.x + outward.x *
|
|
6390
|
-
y: label.anchorPoint.y + outward.y *
|
|
6943
|
+
x: label.anchorPoint.x + outward.x * distance4,
|
|
6944
|
+
y: label.anchorPoint.y + outward.y * distance4
|
|
6391
6945
|
},
|
|
6392
6946
|
center: {
|
|
6393
|
-
x: label.center.x + outward.x *
|
|
6394
|
-
y: label.center.y + outward.y *
|
|
6947
|
+
x: label.center.x + outward.x * distance4,
|
|
6948
|
+
y: label.center.y + outward.y * distance4
|
|
6395
6949
|
}
|
|
6396
6950
|
};
|
|
6397
6951
|
const candidateWithClearance = {
|
|
@@ -6453,16 +7007,16 @@ var createPortOnlyLabelConnectorTrace = ({
|
|
|
6453
7007
|
// lib/solvers/AvailableNetOrientationSolver/constants.ts
|
|
6454
7008
|
var LABEL_SEARCH_STEP = 0.05;
|
|
6455
7009
|
var WICK_CLEARANCE = 1e-3;
|
|
6456
|
-
var
|
|
6457
|
-
var TRACE_BOUNDARY_TOLERANCE = WICK_CLEARANCE +
|
|
7010
|
+
var EPS9 = 1e-9;
|
|
7011
|
+
var TRACE_BOUNDARY_TOLERANCE = WICK_CLEARANCE + EPS9;
|
|
6458
7012
|
var CANDIDATE_SELECTED_COLOR2 = "blue";
|
|
6459
7013
|
var CANDIDATE_REJECTED_COLOR2 = "red";
|
|
6460
7014
|
|
|
6461
7015
|
// lib/solvers/AvailableNetOrientationSolver/geometry.ts
|
|
6462
7016
|
var isYOrientation = (orientation) => orientation === "y+" || orientation === "y-";
|
|
6463
7017
|
var isXOrientation = (orientation) => orientation === "x+" || orientation === "x-";
|
|
6464
|
-
var
|
|
6465
|
-
var rangesOverlap = (minA, maxA, minB, maxB) => Math.min(maxA, maxB) - Math.max(minA, minB) >
|
|
7018
|
+
var rectsOverlap2 = (a, b) => Math.min(a.maxX, b.maxX) - Math.max(a.minX, b.minX) > EPS9 && Math.min(a.maxY, b.maxY) - Math.max(a.minY, b.minY) > EPS9;
|
|
7019
|
+
var rangesOverlap = (minA, maxA, minB, maxB) => Math.min(maxA, maxB) - Math.max(minA, minB) > EPS9;
|
|
6466
7020
|
var traceCrossesBoundsInterior = (bounds, traceMap) => {
|
|
6467
7021
|
for (const trace of Object.values(traceMap)) {
|
|
6468
7022
|
const points = trace.tracePath;
|
|
@@ -6485,7 +7039,7 @@ var segmentCrossesBoundsInterior = (p1, p2, bounds) => {
|
|
|
6485
7039
|
return false;
|
|
6486
7040
|
}
|
|
6487
7041
|
if (sameX2(p1, p2)) {
|
|
6488
|
-
if (p1.x <= interiorBounds.minX +
|
|
7042
|
+
if (p1.x <= interiorBounds.minX + EPS9 || p1.x >= interiorBounds.maxX - EPS9) {
|
|
6489
7043
|
return false;
|
|
6490
7044
|
}
|
|
6491
7045
|
return rangesOverlap(
|
|
@@ -6496,7 +7050,7 @@ var segmentCrossesBoundsInterior = (p1, p2, bounds) => {
|
|
|
6496
7050
|
);
|
|
6497
7051
|
}
|
|
6498
7052
|
if (sameY2(p1, p2)) {
|
|
6499
|
-
if (p1.y <= interiorBounds.minY +
|
|
7053
|
+
if (p1.y <= interiorBounds.minY + EPS9 || p1.y >= interiorBounds.maxY - EPS9) {
|
|
6500
7054
|
return false;
|
|
6501
7055
|
}
|
|
6502
7056
|
return rangesOverlap(
|
|
@@ -6535,7 +7089,7 @@ var getConnectorTracePath = (source, target, orientation) => simplifyOrthogonalP
|
|
|
6535
7089
|
);
|
|
6536
7090
|
var simplifyOrthogonalPath = (path) => {
|
|
6537
7091
|
const deduped = path.filter(
|
|
6538
|
-
(point, index) => index === 0 || !
|
|
7092
|
+
(point, index) => index === 0 || !pointsEqual2(point, path[index - 1])
|
|
6539
7093
|
);
|
|
6540
7094
|
if (deduped.length < 3) return deduped;
|
|
6541
7095
|
const simplified = [deduped[0]];
|
|
@@ -6551,9 +7105,9 @@ var simplifyOrthogonalPath = (path) => {
|
|
|
6551
7105
|
simplified.push(deduped[deduped.length - 1]);
|
|
6552
7106
|
return simplified;
|
|
6553
7107
|
};
|
|
6554
|
-
var
|
|
6555
|
-
var sameX2 = (a, b) => Math.abs(a.x - b.x) <=
|
|
6556
|
-
var sameY2 = (a, b) => Math.abs(a.y - b.y) <=
|
|
7108
|
+
var pointsEqual2 = (a, b) => sameX2(a, b) && sameY2(a, b);
|
|
7109
|
+
var sameX2 = (a, b) => Math.abs(a.x - b.x) <= EPS9;
|
|
7110
|
+
var sameY2 = (a, b) => Math.abs(a.y - b.y) <= EPS9;
|
|
6557
7111
|
var getMaxSearchDistance = (inputProblem) => {
|
|
6558
7112
|
const maxChipWidth = Math.max(
|
|
6559
7113
|
...inputProblem.chips.map((chip) => chip.width),
|
|
@@ -6856,7 +7410,7 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
6856
7410
|
);
|
|
6857
7411
|
const maxSearchDistance = this.getSearchDistanceLimit(label, orientation);
|
|
6858
7412
|
const maxOutwardDistance = outwardDirection.x === 0 && outwardDirection.y === 0 ? 0 : this.maxSearchDistance;
|
|
6859
|
-
for (let outwardDistance = 0; outwardDistance <= maxOutwardDistance +
|
|
7413
|
+
for (let outwardDistance = 0; outwardDistance <= maxOutwardDistance + EPS9; outwardDistance += LABEL_SEARCH_STEP) {
|
|
6860
7414
|
const baseAnchor = {
|
|
6861
7415
|
x: initialBaseAnchor.x + outwardDirection.x * outwardDistance,
|
|
6862
7416
|
y: initialBaseAnchor.y + outwardDirection.y * outwardDistance
|
|
@@ -6929,10 +7483,10 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
6929
7483
|
outwardDistance,
|
|
6930
7484
|
phase = "shift"
|
|
6931
7485
|
} = params;
|
|
6932
|
-
for (let
|
|
7486
|
+
for (let distance4 = LABEL_SEARCH_STEP; distance4 <= maxSearchDistance + EPS9; distance4 += LABEL_SEARCH_STEP) {
|
|
6933
7487
|
const anchorPoint = {
|
|
6934
|
-
x: baseAnchor.x + direction.x *
|
|
6935
|
-
y: baseAnchor.y + direction.y *
|
|
7488
|
+
x: baseAnchor.x + direction.x * distance4,
|
|
7489
|
+
y: baseAnchor.y + direction.y * distance4
|
|
6936
7490
|
};
|
|
6937
7491
|
const candidate = this.createCandidate(label, anchorPoint, orientation);
|
|
6938
7492
|
const result = this.evaluateCandidate(
|
|
@@ -6940,7 +7494,7 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
6940
7494
|
label,
|
|
6941
7495
|
labelIndex,
|
|
6942
7496
|
phase,
|
|
6943
|
-
|
|
7497
|
+
distance4,
|
|
6944
7498
|
outwardDistance
|
|
6945
7499
|
);
|
|
6946
7500
|
this.currentCandidateResults.push(result);
|
|
@@ -6952,11 +7506,11 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
6952
7506
|
}
|
|
6953
7507
|
return null;
|
|
6954
7508
|
}
|
|
6955
|
-
evaluateCandidate(candidate, label, labelIndex, phase,
|
|
7509
|
+
evaluateCandidate(candidate, label, labelIndex, phase, distance4, outwardDistance) {
|
|
6956
7510
|
return {
|
|
6957
7511
|
...candidate,
|
|
6958
7512
|
phase,
|
|
6959
|
-
distance:
|
|
7513
|
+
distance: distance4,
|
|
6960
7514
|
outwardDistance,
|
|
6961
7515
|
selected: false,
|
|
6962
7516
|
status: this.getCandidateStatus({
|
|
@@ -7166,9 +7720,9 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
7166
7720
|
const { anchorPoint, orientation } = candidate;
|
|
7167
7721
|
const chipBounds = chip.bounds;
|
|
7168
7722
|
if (isYOrientation(orientation)) {
|
|
7169
|
-
return anchorPoint.x < chipBounds.minX -
|
|
7723
|
+
return anchorPoint.x < chipBounds.minX - EPS9 || anchorPoint.x > chipBounds.maxX + EPS9;
|
|
7170
7724
|
}
|
|
7171
|
-
return anchorPoint.y < chipBounds.minY -
|
|
7725
|
+
return anchorPoint.y < chipBounds.minY - EPS9 || anchorPoint.y > chipBounds.maxY + EPS9;
|
|
7172
7726
|
});
|
|
7173
7727
|
}
|
|
7174
7728
|
getBoundsStatus(candidateBoundsCheck) {
|
|
@@ -7235,15 +7789,15 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
7235
7789
|
if (i === labelIndex) continue;
|
|
7236
7790
|
const label = this.outputNetLabelPlacements[i];
|
|
7237
7791
|
const otherBounds = getRectBounds(label.center, label.width, label.height);
|
|
7238
|
-
if (
|
|
7792
|
+
if (rectsOverlap2(bounds, otherBounds)) return true;
|
|
7239
7793
|
}
|
|
7240
7794
|
return false;
|
|
7241
7795
|
}
|
|
7242
7796
|
sharesChipBoundary(bounds) {
|
|
7243
7797
|
for (const chip of this.chipObstacleSpatialIndex.chips) {
|
|
7244
7798
|
const chipBounds = chip.bounds;
|
|
7245
|
-
const adjacentToVerticalSide = Math.abs(bounds.minX - chipBounds.maxX) <= WICK_CLEARANCE +
|
|
7246
|
-
const adjacentToHorizontalSide = Math.abs(bounds.minY - chipBounds.maxY) <= WICK_CLEARANCE +
|
|
7799
|
+
const adjacentToVerticalSide = Math.abs(bounds.minX - chipBounds.maxX) <= WICK_CLEARANCE + EPS9 || Math.abs(bounds.maxX - chipBounds.minX) <= WICK_CLEARANCE + EPS9;
|
|
7800
|
+
const adjacentToHorizontalSide = Math.abs(bounds.minY - chipBounds.maxY) <= WICK_CLEARANCE + EPS9 || Math.abs(bounds.maxY - chipBounds.minY) <= WICK_CLEARANCE + EPS9;
|
|
7247
7801
|
if (adjacentToVerticalSide && rangesOverlap(
|
|
7248
7802
|
bounds.minY,
|
|
7249
7803
|
bounds.maxY,
|
|
@@ -7291,13 +7845,13 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
7291
7845
|
let nearestDistance = Number.POSITIVE_INFINITY;
|
|
7292
7846
|
for (const chip of this.chipObstacleSpatialIndex.chips) {
|
|
7293
7847
|
const bounds = chip.bounds;
|
|
7294
|
-
if (point.x < bounds.minX -
|
|
7848
|
+
if (point.x < bounds.minX - EPS9 || point.x > bounds.maxX + EPS9 || point.y < bounds.minY - EPS9 || point.y > bounds.maxY + EPS9) {
|
|
7295
7849
|
continue;
|
|
7296
7850
|
}
|
|
7297
|
-
for (const [side,
|
|
7298
|
-
if (
|
|
7851
|
+
for (const [side, distance4] of getSideDistances(point, bounds)) {
|
|
7852
|
+
if (distance4 < nearestDistance) {
|
|
7299
7853
|
nearestSide = side;
|
|
7300
|
-
nearestDistance =
|
|
7854
|
+
nearestDistance = distance4;
|
|
7301
7855
|
}
|
|
7302
7856
|
}
|
|
7303
7857
|
}
|
|
@@ -7308,8 +7862,8 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
7308
7862
|
let nearestDistanceSq = Number.POSITIVE_INFINITY;
|
|
7309
7863
|
for (const chip of this.chipObstacleSpatialIndex.chips) {
|
|
7310
7864
|
const bounds = chip.bounds;
|
|
7311
|
-
const dx = point.x < bounds.minX -
|
|
7312
|
-
const dy = point.y < bounds.minY -
|
|
7865
|
+
const dx = point.x < bounds.minX - EPS9 ? bounds.minX - point.x : point.x > bounds.maxX + EPS9 ? point.x - bounds.maxX : 0;
|
|
7866
|
+
const dy = point.y < bounds.minY - EPS9 ? bounds.minY - point.y : point.y > bounds.maxY + EPS9 ? point.y - bounds.maxY : 0;
|
|
7313
7867
|
if (dx === 0 && dy === 0) continue;
|
|
7314
7868
|
const distanceSq = dx ** 2 + dy ** 2;
|
|
7315
7869
|
if (distanceSq >= nearestDistanceSq) continue;
|
|
@@ -7326,10 +7880,10 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
7326
7880
|
let nearestSide = null;
|
|
7327
7881
|
let nearestDistance = Number.POSITIVE_INFINITY;
|
|
7328
7882
|
for (const chip of this.chipObstacleSpatialIndex.chips) {
|
|
7329
|
-
for (const [side,
|
|
7330
|
-
if (
|
|
7883
|
+
for (const [side, distance4] of getSideDistances(point, chip.bounds)) {
|
|
7884
|
+
if (distance4 < nearestDistance) {
|
|
7331
7885
|
nearestSide = side;
|
|
7332
|
-
nearestDistance =
|
|
7886
|
+
nearestDistance = distance4;
|
|
7333
7887
|
}
|
|
7334
7888
|
}
|
|
7335
7889
|
}
|
|
@@ -7347,39 +7901,6 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
7347
7901
|
}
|
|
7348
7902
|
};
|
|
7349
7903
|
|
|
7350
|
-
// lib/solvers/RailNetLabelCornerPlacementSolver/geometry.ts
|
|
7351
|
-
var EPS9 = 1e-6;
|
|
7352
|
-
var isTraceLine = (trace) => getUniquePinCount(trace.pinIds) >= 2;
|
|
7353
|
-
var rectsOverlap2 = (a, b) => Math.min(a.maxX, b.maxX) - Math.max(a.minX, b.minX) > EPS9 && Math.min(a.maxY, b.maxY) - Math.max(a.minY, b.minY) > EPS9;
|
|
7354
|
-
var getTraceCorners = (path) => {
|
|
7355
|
-
const corners = [];
|
|
7356
|
-
for (let i = 1; i < path.length - 1; i++) {
|
|
7357
|
-
const previousPoint = path[i - 1];
|
|
7358
|
-
const cornerPoint = path[i];
|
|
7359
|
-
const nextPoint = path[i + 1];
|
|
7360
|
-
if (isTraceCorner(previousPoint, cornerPoint, nextPoint)) {
|
|
7361
|
-
corners.push(cornerPoint);
|
|
7362
|
-
}
|
|
7363
|
-
}
|
|
7364
|
-
return corners;
|
|
7365
|
-
};
|
|
7366
|
-
var tracePathContainsPoint = (path, point) => {
|
|
7367
|
-
for (let i = 0; i < path.length - 1; i++) {
|
|
7368
|
-
if (isPointOnSegment(point, path[i], path[i + 1])) return true;
|
|
7369
|
-
}
|
|
7370
|
-
return false;
|
|
7371
|
-
};
|
|
7372
|
-
var getDistance2 = (a, b) => Math.abs(a.x - b.x) + Math.abs(a.y - b.y);
|
|
7373
|
-
var getUniquePinCount = (pinIds) => new Set(pinIds).size;
|
|
7374
|
-
var isTraceCorner = (a, b, c) => getSegmentOrientation2(a, b) !== getSegmentOrientation2(b, c);
|
|
7375
|
-
var isPointOnSegment = (point, start, end) => {
|
|
7376
|
-
if (getSegmentOrientation2(start, end) === "horizontal") {
|
|
7377
|
-
return Math.abs(point.y - start.y) <= EPS9 && point.x >= Math.min(start.x, end.x) - EPS9 && point.x <= Math.max(start.x, end.x) + EPS9;
|
|
7378
|
-
}
|
|
7379
|
-
return Math.abs(point.x - start.x) <= EPS9 && point.y >= Math.min(start.y, end.y) - EPS9 && point.y <= Math.max(start.y, end.y) + EPS9;
|
|
7380
|
-
};
|
|
7381
|
-
var getSegmentOrientation2 = (a, b) => Math.abs(a.y - b.y) <= EPS9 ? "horizontal" : "vertical";
|
|
7382
|
-
|
|
7383
7904
|
// lib/solvers/RailNetLabelCornerPlacementSolver/visualize.ts
|
|
7384
7905
|
var CANDIDATE_SELECTED_COLOR3 = "blue";
|
|
7385
7906
|
var CANDIDATE_REJECTED_COLOR3 = "red";
|
|
@@ -7602,20 +8123,20 @@ var RailNetLabelCornerPlacementSolver = class extends BaseSolver {
|
|
|
7602
8123
|
}
|
|
7603
8124
|
intersectsAnyChip(bounds) {
|
|
7604
8125
|
return this.inputProblem.chips.some(
|
|
7605
|
-
(chip) =>
|
|
8126
|
+
(chip) => rectsOverlap(bounds, getRectBounds(chip.center, chip.width, chip.height))
|
|
7606
8127
|
);
|
|
7607
8128
|
}
|
|
7608
8129
|
intersectsAnyOtherNetLabel(bounds, labelIndex) {
|
|
7609
8130
|
return this.outputNetLabelPlacements.some((label, index) => {
|
|
7610
8131
|
if (index === labelIndex) return false;
|
|
7611
|
-
return
|
|
8132
|
+
return rectsOverlap(
|
|
7612
8133
|
bounds,
|
|
7613
8134
|
getRectBounds(label.center, label.width, label.height)
|
|
7614
8135
|
);
|
|
7615
8136
|
});
|
|
7616
8137
|
}
|
|
7617
8138
|
getCornerCandidatesForLabel(label) {
|
|
7618
|
-
const
|
|
8139
|
+
const isVertical5 = label.orientation === "y+" || label.orientation === "y-";
|
|
7619
8140
|
const candidates = [];
|
|
7620
8141
|
const seenCornerKeys = /* @__PURE__ */ new Set();
|
|
7621
8142
|
for (const trace of this.getTraceLinesForLabel(label)) {
|
|
@@ -7626,14 +8147,14 @@ var RailNetLabelCornerPlacementSolver = class extends BaseSolver {
|
|
|
7626
8147
|
if (seenCornerKeys.has(key)) continue;
|
|
7627
8148
|
seenCornerKeys.add(key);
|
|
7628
8149
|
const pinAligned = pins.some((pin) => {
|
|
7629
|
-
if (
|
|
7630
|
-
return Math.abs(pin.y - anchorPoint.y) <
|
|
8150
|
+
if (isVertical5) return Math.abs(pin.x - anchorPoint.x) < EPS5;
|
|
8151
|
+
return Math.abs(pin.y - anchorPoint.y) < EPS5;
|
|
7631
8152
|
});
|
|
7632
8153
|
if (!pinAligned) continue;
|
|
7633
8154
|
candidates.push({
|
|
7634
8155
|
anchorPoint,
|
|
7635
8156
|
traceId: trace.mspPairId,
|
|
7636
|
-
distance:
|
|
8157
|
+
distance: getDistance(anchorPoint, label.anchorPoint),
|
|
7637
8158
|
pinAligned
|
|
7638
8159
|
});
|
|
7639
8160
|
}
|
|
@@ -7763,17 +8284,17 @@ var getTraceLength = (trace) => {
|
|
|
7763
8284
|
}
|
|
7764
8285
|
return length;
|
|
7765
8286
|
};
|
|
7766
|
-
var getPointAtTraceDistance = (trace,
|
|
8287
|
+
var getPointAtTraceDistance = (trace, distance4) => {
|
|
7767
8288
|
let pathDistance = 0;
|
|
7768
8289
|
for (let i = 0; i < trace.tracePath.length - 1; i++) {
|
|
7769
8290
|
const start = trace.tracePath[i];
|
|
7770
8291
|
const end = trace.tracePath[i + 1];
|
|
7771
8292
|
const segmentLength = getManhattanDistance(start, end);
|
|
7772
8293
|
const nextDistance = pathDistance + segmentLength;
|
|
7773
|
-
if (
|
|
8294
|
+
if (distance4 <= nextDistance + EPS10) {
|
|
7774
8295
|
const offset = Math.max(
|
|
7775
8296
|
0,
|
|
7776
|
-
Math.min(segmentLength,
|
|
8297
|
+
Math.min(segmentLength, distance4 - pathDistance)
|
|
7777
8298
|
);
|
|
7778
8299
|
const direction = getSegmentDirection(start, end);
|
|
7779
8300
|
return {
|
|
@@ -7808,7 +8329,7 @@ var segmentCrossesBoundsInterior2 = (start, end, bounds) => {
|
|
|
7808
8329
|
if (interior.minX >= interior.maxX || interior.minY >= interior.maxY) {
|
|
7809
8330
|
return false;
|
|
7810
8331
|
}
|
|
7811
|
-
if (
|
|
8332
|
+
if (isVertical4(start, end)) {
|
|
7812
8333
|
if (start.x <= interior.minX + EPS10 || start.x >= interior.maxX - EPS10) {
|
|
7813
8334
|
return false;
|
|
7814
8335
|
}
|
|
@@ -7819,7 +8340,7 @@ var segmentCrossesBoundsInterior2 = (start, end, bounds) => {
|
|
|
7819
8340
|
interior.maxY
|
|
7820
8341
|
);
|
|
7821
8342
|
}
|
|
7822
|
-
if (
|
|
8343
|
+
if (isHorizontal3(start, end)) {
|
|
7823
8344
|
if (start.y <= interior.minY + EPS10 || start.y >= interior.maxY - EPS10) {
|
|
7824
8345
|
return false;
|
|
7825
8346
|
}
|
|
@@ -7833,20 +8354,20 @@ var segmentCrossesBoundsInterior2 = (start, end, bounds) => {
|
|
|
7833
8354
|
return false;
|
|
7834
8355
|
};
|
|
7835
8356
|
var isPointOnSegment2 = (point, start, end) => {
|
|
7836
|
-
if (
|
|
8357
|
+
if (isHorizontal3(start, end)) {
|
|
7837
8358
|
return Math.abs(point.y - start.y) <= EPS10 && point.x >= Math.min(start.x, end.x) - EPS10 && point.x <= Math.max(start.x, end.x) + EPS10;
|
|
7838
8359
|
}
|
|
7839
|
-
if (
|
|
8360
|
+
if (isVertical4(start, end)) {
|
|
7840
8361
|
return Math.abs(point.x - start.x) <= EPS10 && point.y >= Math.min(start.y, end.y) - EPS10 && point.y <= Math.max(start.y, end.y) + EPS10;
|
|
7841
8362
|
}
|
|
7842
8363
|
return false;
|
|
7843
8364
|
};
|
|
7844
8365
|
var getSegmentDirection = (start, end) => ({
|
|
7845
|
-
x:
|
|
7846
|
-
y:
|
|
8366
|
+
x: isVertical4(start, end) ? 0 : Math.sign(end.x - start.x),
|
|
8367
|
+
y: isHorizontal3(start, end) ? 0 : Math.sign(end.y - start.y)
|
|
7847
8368
|
});
|
|
7848
|
-
var
|
|
7849
|
-
var
|
|
8369
|
+
var isHorizontal3 = (start, end) => Math.abs(start.y - end.y) <= EPS10;
|
|
8370
|
+
var isVertical4 = (start, end) => Math.abs(start.x - end.x) <= EPS10;
|
|
7850
8371
|
var rangesOverlap2 = (minA, maxA, minB, maxB) => Math.min(maxA, maxB) - Math.max(minA, minB) > EPS10;
|
|
7851
8372
|
var getUniquePinCount2 = (pinIds) => new Set(pinIds).size;
|
|
7852
8373
|
|
|
@@ -7898,13 +8419,13 @@ var getCandidateDistances = (traceLength, vertexDistances) => {
|
|
|
7898
8419
|
const distances = /* @__PURE__ */ new Set();
|
|
7899
8420
|
const maxSteps = Math.ceil(traceLength / CANDIDATE_STEP);
|
|
7900
8421
|
for (let i = 0; i <= maxSteps; i++) {
|
|
7901
|
-
const
|
|
7902
|
-
distances.add(roundDistance(
|
|
8422
|
+
const distance4 = Math.min(traceLength, i * CANDIDATE_STEP);
|
|
8423
|
+
distances.add(roundDistance(distance4));
|
|
7903
8424
|
}
|
|
7904
|
-
for (const
|
|
7905
|
-
distances.add(roundDistance(
|
|
8425
|
+
for (const distance4 of vertexDistances) {
|
|
8426
|
+
distances.add(roundDistance(distance4));
|
|
7906
8427
|
}
|
|
7907
|
-
return [...distances].filter((
|
|
8428
|
+
return [...distances].filter((distance4) => distance4 >= -EPS10 && distance4 <= traceLength + EPS10).sort((a, b) => a - b);
|
|
7908
8429
|
};
|
|
7909
8430
|
var getOrientationsForPoint = (params) => {
|
|
7910
8431
|
const { inputProblem, label, point, orientationConstraint } = params;
|
|
@@ -8082,7 +8603,7 @@ var getNetLabelHeight = (inputProblem, label) => {
|
|
|
8082
8603
|
(nc) => nc.pinIds.some((pid) => label.pinIds.includes(pid))
|
|
8083
8604
|
)?.netLabelHeight;
|
|
8084
8605
|
};
|
|
8085
|
-
var roundDistance = (
|
|
8606
|
+
var roundDistance = (distance4) => Number(distance4.toFixed(6));
|
|
8086
8607
|
var isSamePlacement = (label, point, orientation) => Math.abs(point.x - label.anchorPoint.x) <= EPS10 && Math.abs(point.y - label.anchorPoint.y) <= EPS10 && orientation === label.orientation;
|
|
8087
8608
|
|
|
8088
8609
|
// lib/solvers/TraceAnchoredNetLabelOverlapSolver/visualize.ts
|
|
@@ -8855,11 +9376,11 @@ var NetLabelNetLabelCollisionSolver = class extends BaseSolver {
|
|
|
8855
9376
|
for (let si = 0; si < pts.length - 1; si++) {
|
|
8856
9377
|
const segStart = pts[si];
|
|
8857
9378
|
const segEnd = pts[si + 1];
|
|
8858
|
-
const
|
|
8859
|
-
const
|
|
8860
|
-
if (!
|
|
9379
|
+
const isHorizontal4 = Math.abs(segStart.y - segEnd.y) < SEGMENT_PARALLEL_EPS;
|
|
9380
|
+
const isVertical5 = Math.abs(segStart.x - segEnd.x) < SEGMENT_PARALLEL_EPS;
|
|
9381
|
+
if (!isHorizontal4 && !isVertical5) continue;
|
|
8861
9382
|
let perpendicularOrientations;
|
|
8862
|
-
if (
|
|
9383
|
+
if (isHorizontal4) {
|
|
8863
9384
|
perpendicularOrientations = ["y+", "y-"];
|
|
8864
9385
|
} else {
|
|
8865
9386
|
perpendicularOrientations = ["x+", "x-"];
|
|
@@ -9072,7 +9593,9 @@ var SchematicTracePipelineSolver = class extends BaseSolver {
|
|
|
9072
9593
|
availableNetOrientationSolver;
|
|
9073
9594
|
railNetLabelCornerPlacementSolver;
|
|
9074
9595
|
traceAnchoredNetLabelOverlapSolver;
|
|
9596
|
+
preAlignmentNetLabelTraceCollisionSolver;
|
|
9075
9597
|
netLabelTraceCollisionSolver;
|
|
9598
|
+
traceCleanupSolver2;
|
|
9076
9599
|
netLabelNetLabelCollisionSolver;
|
|
9077
9600
|
startTimeOfPhase;
|
|
9078
9601
|
endTimeOfPhase;
|
|
@@ -9257,7 +9780,7 @@ var SchematicTracePipelineSolver = class extends BaseSolver {
|
|
|
9257
9780
|
]
|
|
9258
9781
|
),
|
|
9259
9782
|
definePipelineStep(
|
|
9260
|
-
"
|
|
9783
|
+
"preAlignmentNetLabelTraceCollisionSolver",
|
|
9261
9784
|
NetLabelTraceCollisionSolver,
|
|
9262
9785
|
(instance) => [
|
|
9263
9786
|
{
|
|
@@ -9267,6 +9790,41 @@ var SchematicTracePipelineSolver = class extends BaseSolver {
|
|
|
9267
9790
|
}
|
|
9268
9791
|
]
|
|
9269
9792
|
),
|
|
9793
|
+
definePipelineStep(
|
|
9794
|
+
"traceCleanupSolver2",
|
|
9795
|
+
TraceCleanupSolver,
|
|
9796
|
+
(instance) => {
|
|
9797
|
+
const collisionOutput = instance.preAlignmentNetLabelTraceCollisionSolver.getOutput();
|
|
9798
|
+
const labelMergingOutput = instance.traceLabelOverlapAvoidanceSolver.labelMergingSolver.getOutput();
|
|
9799
|
+
return [
|
|
9800
|
+
{
|
|
9801
|
+
inputProblem: instance.inputProblem,
|
|
9802
|
+
allTraces: collisionOutput.traces,
|
|
9803
|
+
allLabelPlacements: collisionOutput.netLabelPlacements,
|
|
9804
|
+
mergedLabelNetIdMap: labelMergingOutput.mergedLabelNetIdMap,
|
|
9805
|
+
paddingBuffer: 0.1,
|
|
9806
|
+
operations: ["aligning_same_net_rails"],
|
|
9807
|
+
eligibleTraceIds: new Set(
|
|
9808
|
+
instance.traceCleanupSolver.getOutput().traces.map((trace) => trace.mspPairId)
|
|
9809
|
+
)
|
|
9810
|
+
}
|
|
9811
|
+
];
|
|
9812
|
+
}
|
|
9813
|
+
),
|
|
9814
|
+
definePipelineStep(
|
|
9815
|
+
"netLabelTraceCollisionSolver",
|
|
9816
|
+
NetLabelTraceCollisionSolver,
|
|
9817
|
+
(instance) => {
|
|
9818
|
+
const previousCollisionOutput = instance.preAlignmentNetLabelTraceCollisionSolver.getOutput();
|
|
9819
|
+
return [
|
|
9820
|
+
{
|
|
9821
|
+
inputProblem: instance.inputProblem,
|
|
9822
|
+
traces: instance.traceCleanupSolver2.getOutput().traces,
|
|
9823
|
+
netLabelPlacements: previousCollisionOutput.netLabelPlacements
|
|
9824
|
+
}
|
|
9825
|
+
];
|
|
9826
|
+
}
|
|
9827
|
+
),
|
|
9270
9828
|
definePipelineStep(
|
|
9271
9829
|
"netLabelNetLabelCollisionSolver",
|
|
9272
9830
|
NetLabelNetLabelCollisionSolver,
|