@tscircuit/schematic-trace-solver 0.0.52 → 0.0.54
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 +0 -3
- package/dist/index.js +135 -156
- package/lib/solvers/AvailableNetOrientationSolver/AvailableNetOrientationSolver.ts +3 -39
- package/lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver.ts +2 -0
- package/lib/solvers/SchematicTracePipelineSolver/colorAvailableNetOrientationLabels.ts +54 -0
- package/lib/solvers/TraceAnchoredNetLabelOverlapSolver/TraceAnchoredNetLabelOverlapSolver.ts +6 -6
- package/lib/solvers/TraceAnchoredNetLabelOverlapSolver/candidates.ts +63 -105
- package/lib/solvers/TraceAnchoredNetLabelOverlapSolver/geometry.ts +4 -0
- package/lib/solvers/TraceAnchoredNetLabelOverlapSolver/visualize.ts +38 -4
- package/package.json +1 -1
- package/tests/assets/example30.json +4 -1
- package/tests/examples/__snapshots__/example01.snap.svg +6 -3
- package/tests/examples/__snapshots__/example02.snap.svg +8 -4
- package/tests/examples/__snapshots__/example04.snap.svg +4 -2
- package/tests/examples/__snapshots__/example07.snap.svg +10 -5
- package/tests/examples/__snapshots__/example12.snap.svg +8 -4
- package/tests/examples/__snapshots__/example13.snap.svg +16 -8
- package/tests/examples/__snapshots__/example14.snap.svg +16 -8
- package/tests/examples/__snapshots__/example15.snap.svg +18 -9
- package/tests/examples/__snapshots__/example16.snap.svg +8 -4
- package/tests/examples/__snapshots__/example17.snap.svg +9 -5
- package/tests/examples/__snapshots__/example18.snap.svg +10 -5
- package/tests/examples/__snapshots__/example20.snap.svg +6 -3
- package/tests/examples/__snapshots__/example21.snap.svg +17 -12
- package/tests/examples/__snapshots__/example22.snap.svg +8 -4
- package/tests/examples/__snapshots__/example25.snap.svg +18 -9
- package/tests/examples/__snapshots__/example30.snap.svg +74 -62
- package/tests/examples/__snapshots__/example31.snap.svg +2 -1
- package/tests/fixtures/matcher.ts +21 -0
package/dist/index.d.ts
CHANGED
|
@@ -691,11 +691,8 @@ declare class AvailableNetOrientationSolver extends BaseSolver {
|
|
|
691
691
|
private getSearchDistanceLimit;
|
|
692
692
|
private createCandidate;
|
|
693
693
|
private getNetLabelWidth;
|
|
694
|
-
private isLabelPlacementValid;
|
|
695
|
-
private isCandidateValidWithOffset;
|
|
696
694
|
private getCandidateStatus;
|
|
697
695
|
private getBoundsStatus;
|
|
698
|
-
private getOffsetCollisionBounds;
|
|
699
696
|
private intersectsAnyOtherNetLabel;
|
|
700
697
|
private sharesChipBoundary;
|
|
701
698
|
private getChipSideForPoint;
|
package/dist/index.js
CHANGED
|
@@ -2273,6 +2273,44 @@ orientation: ${p.orientation}`
|
|
|
2273
2273
|
}
|
|
2274
2274
|
};
|
|
2275
2275
|
|
|
2276
|
+
// lib/solvers/SchematicTracePipelineSolver/colorAvailableNetOrientationLabels.ts
|
|
2277
|
+
var AVAILABLE_Y_PLUS_COLOR = "#ef4444";
|
|
2278
|
+
var AVAILABLE_Y_MINUS_COLOR = "#000000";
|
|
2279
|
+
var AVAILABLE_ORIENTATION_FILL_ALPHA = "66";
|
|
2280
|
+
var colorAvailableNetOrientationLabels = (graphicsObject, inputProblem) => {
|
|
2281
|
+
const availableOrientations = inputProblem.availableNetLabelOrientations;
|
|
2282
|
+
if (!availableOrientations) return;
|
|
2283
|
+
for (const rect of graphicsObject.rects ?? []) {
|
|
2284
|
+
const orientations = getAvailableOrientationsForRect(
|
|
2285
|
+
rect.label,
|
|
2286
|
+
availableOrientations
|
|
2287
|
+
);
|
|
2288
|
+
if (!orientations) continue;
|
|
2289
|
+
const hasYPlus = orientations.includes("y+");
|
|
2290
|
+
const hasYMinus = orientations.includes("y-");
|
|
2291
|
+
if (hasYPlus === hasYMinus) continue;
|
|
2292
|
+
const color = hasYPlus ? AVAILABLE_Y_PLUS_COLOR : AVAILABLE_Y_MINUS_COLOR;
|
|
2293
|
+
rect.fill = `${color}${AVAILABLE_ORIENTATION_FILL_ALPHA}`;
|
|
2294
|
+
rect.stroke = color;
|
|
2295
|
+
rect.color = color;
|
|
2296
|
+
}
|
|
2297
|
+
};
|
|
2298
|
+
var getAvailableOrientationsForRect = (label, availableOrientations) => {
|
|
2299
|
+
for (const netId of getNetIdsFromRectLabel(label)) {
|
|
2300
|
+
if (Object.hasOwn(availableOrientations, netId)) {
|
|
2301
|
+
return availableOrientations[netId];
|
|
2302
|
+
}
|
|
2303
|
+
}
|
|
2304
|
+
return void 0;
|
|
2305
|
+
};
|
|
2306
|
+
var getNetIdsFromRectLabel = (label) => {
|
|
2307
|
+
if (!label) return [];
|
|
2308
|
+
return [
|
|
2309
|
+
label.match(/^netId: (.+)$/m)?.[1],
|
|
2310
|
+
label.match(/^globalConnNetId: (.+)$/m)?.[1]
|
|
2311
|
+
].filter((netId) => Boolean(netId && netId !== "undefined"));
|
|
2312
|
+
};
|
|
2313
|
+
|
|
2276
2314
|
// lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/LabelMergingSolver/groupLabelsByChipAndOrientation.ts
|
|
2277
2315
|
var groupLabelsByChipAndOrientation = ({
|
|
2278
2316
|
labels,
|
|
@@ -5641,16 +5679,15 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
5641
5679
|
getProcessableLabelIndices() {
|
|
5642
5680
|
const indices = [];
|
|
5643
5681
|
for (let i = 0; i < this.outputNetLabelPlacements.length; i++) {
|
|
5644
|
-
if (this.shouldProcessLabel(this.outputNetLabelPlacements[i]
|
|
5682
|
+
if (this.shouldProcessLabel(this.outputNetLabelPlacements[i])) {
|
|
5645
5683
|
indices.push(i);
|
|
5646
5684
|
}
|
|
5647
5685
|
}
|
|
5648
5686
|
return indices;
|
|
5649
5687
|
}
|
|
5650
|
-
shouldProcessLabel(label
|
|
5688
|
+
shouldProcessLabel(label) {
|
|
5651
5689
|
const orientations = this.getAvailableOrientations(label);
|
|
5652
|
-
|
|
5653
|
-
return !(orientations.includes(label.orientation) && this.isLabelPlacementValid(label, labelIndex));
|
|
5690
|
+
return orientations.length > 0 && !orientations.includes(label.orientation);
|
|
5654
5691
|
}
|
|
5655
5692
|
processLabel(labelIndex) {
|
|
5656
5693
|
const label = this.outputNetLabelPlacements[labelIndex];
|
|
@@ -5879,22 +5916,6 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
5879
5916
|
(connection) => connection.netId === label.netId
|
|
5880
5917
|
)?.netLabelWidth;
|
|
5881
5918
|
}
|
|
5882
|
-
isLabelPlacementValid(label, labelIndex) {
|
|
5883
|
-
return this.isCandidateValidWithOffset(
|
|
5884
|
-
{
|
|
5885
|
-
orientation: label.orientation,
|
|
5886
|
-
anchorPoint: label.anchorPoint,
|
|
5887
|
-
center: label.center,
|
|
5888
|
-
width: label.width,
|
|
5889
|
-
height: label.height
|
|
5890
|
-
},
|
|
5891
|
-
labelIndex
|
|
5892
|
-
);
|
|
5893
|
-
}
|
|
5894
|
-
isCandidateValidWithOffset(candidate, labelIndex) {
|
|
5895
|
-
const bounds = this.getOffsetCollisionBounds(candidate);
|
|
5896
|
-
return this.getBoundsStatus(bounds, labelIndex) === "valid";
|
|
5897
|
-
}
|
|
5898
5919
|
getCandidateStatus(candidate, label, labelIndex) {
|
|
5899
5920
|
const boundsStatus = this.getBoundsStatus(
|
|
5900
5921
|
getRectBounds(candidate.center, candidate.width, candidate.height),
|
|
@@ -5928,15 +5949,6 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
5928
5949
|
}
|
|
5929
5950
|
return "valid";
|
|
5930
5951
|
}
|
|
5931
|
-
getOffsetCollisionBounds(candidate) {
|
|
5932
|
-
const direction = dir(candidate.orientation);
|
|
5933
|
-
const collisionTestOffset = 1e-4;
|
|
5934
|
-
const testCenter = {
|
|
5935
|
-
x: candidate.center.x + direction.x * collisionTestOffset,
|
|
5936
|
-
y: candidate.center.y + direction.y * collisionTestOffset
|
|
5937
|
-
};
|
|
5938
|
-
return getRectBounds(testCenter, candidate.width, candidate.height);
|
|
5939
|
-
}
|
|
5940
5952
|
intersectsAnyOtherNetLabel(bounds, labelIndex) {
|
|
5941
5953
|
for (let i = 0; i < this.outputNetLabelPlacements.length; i++) {
|
|
5942
5954
|
if (i === labelIndex) continue;
|
|
@@ -6367,6 +6379,7 @@ var EPS8 = 1e-6;
|
|
|
6367
6379
|
var TRACE_BOUNDARY_TOLERANCE2 = 1e-6;
|
|
6368
6380
|
var getLabelBounds = (label) => getRectBounds(label.center, label.width, label.height);
|
|
6369
6381
|
var rectsOverlap3 = (a, b) => Math.min(a.maxX, b.maxX) - Math.max(a.minX, b.minX) > EPS8 && Math.min(a.maxY, b.maxY) - Math.max(a.minY, b.minY) > EPS8;
|
|
6382
|
+
var rectsTouchOrOverlap = (a, b) => Math.min(a.maxX, b.maxX) - Math.max(a.minX, b.minX) >= -EPS8 && Math.min(a.maxY, b.maxY) - Math.max(a.minY, b.minY) >= -EPS8;
|
|
6370
6383
|
var traceCrossesBoundsInterior2 = (bounds, traces) => {
|
|
6371
6384
|
for (const trace of traces) {
|
|
6372
6385
|
const points = trace.tracePath;
|
|
@@ -6439,41 +6452,7 @@ var getTraceVertexDistances = (trace) => {
|
|
|
6439
6452
|
}
|
|
6440
6453
|
return distances;
|
|
6441
6454
|
};
|
|
6442
|
-
var getTraceDistanceCompatibleOrientations = (trace, distance3) => {
|
|
6443
|
-
const orientations = /* @__PURE__ */ new Set();
|
|
6444
|
-
let pathDistance = 0;
|
|
6445
|
-
for (let i = 0; i < trace.tracePath.length - 1; i++) {
|
|
6446
|
-
const start = trace.tracePath[i];
|
|
6447
|
-
const end = trace.tracePath[i + 1];
|
|
6448
|
-
const segmentLength = getManhattanDistance(start, end);
|
|
6449
|
-
const nextDistance = pathDistance + segmentLength;
|
|
6450
|
-
if (distance3 >= pathDistance - EPS8 && distance3 <= nextDistance + EPS8) {
|
|
6451
|
-
addSegmentCompatibleOrientations(orientations, trace, i);
|
|
6452
|
-
if (Math.abs(distance3 - pathDistance) <= EPS8) {
|
|
6453
|
-
addSegmentCompatibleOrientations(orientations, trace, i - 1);
|
|
6454
|
-
}
|
|
6455
|
-
if (Math.abs(distance3 - nextDistance) <= EPS8) {
|
|
6456
|
-
addSegmentCompatibleOrientations(orientations, trace, i + 1);
|
|
6457
|
-
}
|
|
6458
|
-
return orientations;
|
|
6459
|
-
}
|
|
6460
|
-
pathDistance = nextDistance;
|
|
6461
|
-
}
|
|
6462
|
-
return orientations;
|
|
6463
|
-
};
|
|
6464
6455
|
var getManhattanDistance = (a, b) => Math.abs(a.x - b.x) + Math.abs(a.y - b.y);
|
|
6465
|
-
var addSegmentCompatibleOrientations = (orientations, trace, segmentIndex) => {
|
|
6466
|
-
const start = trace.tracePath[segmentIndex];
|
|
6467
|
-
const end = trace.tracePath[segmentIndex + 1];
|
|
6468
|
-
if (!start || !end) return;
|
|
6469
|
-
if (isHorizontal2(start, end)) {
|
|
6470
|
-
orientations.add("y+");
|
|
6471
|
-
orientations.add("y-");
|
|
6472
|
-
} else if (isVertical3(start, end)) {
|
|
6473
|
-
orientations.add("x+");
|
|
6474
|
-
orientations.add("x-");
|
|
6475
|
-
}
|
|
6476
|
-
};
|
|
6477
6456
|
var segmentCrossesBoundsInterior2 = (start, end, bounds) => {
|
|
6478
6457
|
const interior = {
|
|
6479
6458
|
minX: bounds.minX + TRACE_BOUNDARY_TOLERANCE2,
|
|
@@ -6533,25 +6512,18 @@ var generateCandidatesAlongTrace = (params) => {
|
|
|
6533
6512
|
const traceLength = getTraceLength(traceLocation.trace);
|
|
6534
6513
|
const orientationConstraint = getOrientationConstraint(inputProblem, label);
|
|
6535
6514
|
const candidateDistances = getCandidateDistances(
|
|
6536
|
-
traceLocation,
|
|
6537
6515
|
traceLength,
|
|
6538
|
-
getTraceVertexDistances(traceLocation.trace)
|
|
6539
|
-
orientationConstraint
|
|
6516
|
+
getTraceVertexDistances(traceLocation.trace)
|
|
6540
6517
|
);
|
|
6541
6518
|
const netLabelWidth = getNetLabelWidth(inputProblem, label);
|
|
6542
6519
|
const candidates = [];
|
|
6543
6520
|
const seenCandidateKeys = /* @__PURE__ */ new Set();
|
|
6544
6521
|
for (const pathDistance of candidateDistances) {
|
|
6545
6522
|
const point = getPointAtTraceDistance(traceLocation.trace, pathDistance);
|
|
6546
|
-
const compatibleOrientations = getTraceDistanceCompatibleOrientations(
|
|
6547
|
-
traceLocation.trace,
|
|
6548
|
-
pathDistance
|
|
6549
|
-
);
|
|
6550
6523
|
const orientations = getOrientationsForPoint({
|
|
6551
6524
|
inputProblem,
|
|
6552
6525
|
label,
|
|
6553
6526
|
point,
|
|
6554
|
-
compatibleOrientations,
|
|
6555
6527
|
orientationConstraint
|
|
6556
6528
|
});
|
|
6557
6529
|
for (const orientation of orientations) {
|
|
@@ -6573,11 +6545,9 @@ var generateCandidatesAlongTrace = (params) => {
|
|
|
6573
6545
|
);
|
|
6574
6546
|
}
|
|
6575
6547
|
}
|
|
6576
|
-
return candidates
|
|
6577
|
-
(a, b) => a.distanceFromOriginal - b.distanceFromOriginal || a.pathDistance - b.pathDistance
|
|
6578
|
-
);
|
|
6548
|
+
return candidates;
|
|
6579
6549
|
};
|
|
6580
|
-
var getCandidateDistances = (
|
|
6550
|
+
var getCandidateDistances = (traceLength, vertexDistances) => {
|
|
6581
6551
|
const distances = /* @__PURE__ */ new Set();
|
|
6582
6552
|
const maxSteps = Math.ceil(traceLength / CANDIDATE_STEP);
|
|
6583
6553
|
for (let i = 0; i <= maxSteps; i++) {
|
|
@@ -6587,35 +6557,17 @@ var getCandidateDistances = (traceLocation, traceLength, vertexDistances, orient
|
|
|
6587
6557
|
for (const distance3 of vertexDistances) {
|
|
6588
6558
|
distances.add(roundDistance(distance3));
|
|
6589
6559
|
}
|
|
6590
|
-
distances.
|
|
6591
|
-
return [...distances].filter((distance3) => distance3 >= -EPS8 && distance3 <= traceLength + EPS8).filter(
|
|
6592
|
-
(distance3) => isDistanceAllowedByOrientationConstraint(
|
|
6593
|
-
traceLocation,
|
|
6594
|
-
distance3,
|
|
6595
|
-
orientationConstraint
|
|
6596
|
-
)
|
|
6597
|
-
).sort(
|
|
6598
|
-
(a, b) => Math.abs(a - traceLocation.distance) - Math.abs(b - traceLocation.distance) || a - b
|
|
6599
|
-
);
|
|
6560
|
+
return [...distances].filter((distance3) => distance3 >= -EPS8 && distance3 <= traceLength + EPS8).sort((a, b) => a - b);
|
|
6600
6561
|
};
|
|
6601
6562
|
var getOrientationsForPoint = (params) => {
|
|
6602
|
-
const {
|
|
6603
|
-
inputProblem,
|
|
6604
|
-
label,
|
|
6605
|
-
point,
|
|
6606
|
-
compatibleOrientations,
|
|
6607
|
-
orientationConstraint
|
|
6608
|
-
} = params;
|
|
6563
|
+
const { inputProblem, label, point, orientationConstraint } = params;
|
|
6609
6564
|
if (orientationConstraint) {
|
|
6610
|
-
return orientationConstraint
|
|
6611
|
-
(orientation) => compatibleOrientations.has(orientation)
|
|
6612
|
-
);
|
|
6565
|
+
return orientationConstraint;
|
|
6613
6566
|
}
|
|
6614
6567
|
return getUnconstrainedOrientations({
|
|
6615
6568
|
label,
|
|
6616
6569
|
inputProblem,
|
|
6617
|
-
point
|
|
6618
|
-
compatibleOrientations
|
|
6570
|
+
point
|
|
6619
6571
|
});
|
|
6620
6572
|
};
|
|
6621
6573
|
var createCandidate = (params) => {
|
|
@@ -6645,23 +6597,18 @@ var createCandidate = (params) => {
|
|
|
6645
6597
|
};
|
|
6646
6598
|
};
|
|
6647
6599
|
var getOrientationConstraint = (inputProblem, label) => {
|
|
6600
|
+
const availableOrientations = inputProblem.availableNetLabelOrientations ?? {};
|
|
6648
6601
|
for (const netId of getOrientationConstraintKeys(inputProblem, label)) {
|
|
6649
|
-
if (Object.hasOwn(
|
|
6650
|
-
return
|
|
6602
|
+
if (Object.hasOwn(availableOrientations, netId)) {
|
|
6603
|
+
return dedupeOrientations(
|
|
6604
|
+
(availableOrientations[netId] ?? []).map(normalizeFacingDirection).filter(
|
|
6605
|
+
(orientation) => orientation !== void 0
|
|
6606
|
+
)
|
|
6607
|
+
);
|
|
6651
6608
|
}
|
|
6652
6609
|
}
|
|
6653
6610
|
return null;
|
|
6654
6611
|
};
|
|
6655
|
-
var isDistanceAllowedByOrientationConstraint = (traceLocation, distance3, constrainedOrientations) => {
|
|
6656
|
-
if (!constrainedOrientations) return true;
|
|
6657
|
-
const compatibleOrientations = getTraceDistanceCompatibleOrientations(
|
|
6658
|
-
traceLocation.trace,
|
|
6659
|
-
distance3
|
|
6660
|
-
);
|
|
6661
|
-
return constrainedOrientations.some(
|
|
6662
|
-
(orientation) => compatibleOrientations.has(orientation)
|
|
6663
|
-
);
|
|
6664
|
-
};
|
|
6665
6612
|
var getOrientationConstraintKeys = (inputProblem, label) => dedupeStrings([
|
|
6666
6613
|
label.netId,
|
|
6667
6614
|
label.globalConnNetId,
|
|
@@ -6670,55 +6617,49 @@ var getOrientationConstraintKeys = (inputProblem, label) => dedupeStrings([
|
|
|
6670
6617
|
).map((connection) => connection.netId)
|
|
6671
6618
|
]);
|
|
6672
6619
|
var getUnconstrainedOrientations = (params) => {
|
|
6673
|
-
const { label, inputProblem, point
|
|
6620
|
+
const { label, inputProblem, point } = params;
|
|
6674
6621
|
return dedupeOrientations([
|
|
6675
|
-
...getInitialOrientations(label
|
|
6622
|
+
...getInitialOrientations(label),
|
|
6676
6623
|
...getOutwardOrientations({
|
|
6677
6624
|
inputProblem,
|
|
6678
|
-
point
|
|
6679
|
-
compatibleOrientations
|
|
6625
|
+
point
|
|
6680
6626
|
}),
|
|
6681
|
-
...ALL_ORIENTATIONS
|
|
6682
|
-
(orientation) => compatibleOrientations.has(orientation)
|
|
6683
|
-
)
|
|
6627
|
+
...ALL_ORIENTATIONS
|
|
6684
6628
|
]);
|
|
6685
6629
|
};
|
|
6686
|
-
var getInitialOrientations = (label
|
|
6687
|
-
|
|
6688
|
-
)
|
|
6630
|
+
var getInitialOrientations = (label) => [
|
|
6631
|
+
label.orientation,
|
|
6632
|
+
getFlippedOrientation(label.orientation)
|
|
6633
|
+
];
|
|
6689
6634
|
var getOutwardOrientations = (params) => {
|
|
6690
|
-
const { inputProblem, point
|
|
6635
|
+
const { inputProblem, point } = params;
|
|
6691
6636
|
const chipBounds = getChipBounds(inputProblem);
|
|
6692
6637
|
return dedupeOrientations(
|
|
6693
|
-
getOutwardOrientationOptions(point, chipBounds
|
|
6638
|
+
getOutwardOrientationOptions(point, chipBounds).sort((a, b) => b.outwardScore - a.outwardScore).map(({ orientation }) => orientation)
|
|
6694
6639
|
);
|
|
6695
6640
|
};
|
|
6696
|
-
var getOutwardOrientationOptions = (point, chipBounds
|
|
6641
|
+
var getOutwardOrientationOptions = (point, chipBounds) => {
|
|
6697
6642
|
const options = [];
|
|
6698
|
-
|
|
6699
|
-
|
|
6700
|
-
|
|
6701
|
-
|
|
6702
|
-
|
|
6703
|
-
|
|
6704
|
-
|
|
6705
|
-
|
|
6706
|
-
|
|
6707
|
-
|
|
6708
|
-
|
|
6709
|
-
|
|
6710
|
-
|
|
6711
|
-
|
|
6712
|
-
|
|
6713
|
-
|
|
6714
|
-
|
|
6715
|
-
|
|
6716
|
-
|
|
6717
|
-
|
|
6718
|
-
negativeOrientation: "x-"
|
|
6719
|
-
})
|
|
6720
|
-
);
|
|
6721
|
-
}
|
|
6643
|
+
options.push(
|
|
6644
|
+
getOutwardAxisOption({
|
|
6645
|
+
value: point.y,
|
|
6646
|
+
min: chipBounds.minY,
|
|
6647
|
+
max: chipBounds.maxY,
|
|
6648
|
+
center: chipBounds.centerY,
|
|
6649
|
+
positiveOrientation: "y+",
|
|
6650
|
+
negativeOrientation: "y-"
|
|
6651
|
+
})
|
|
6652
|
+
);
|
|
6653
|
+
options.push(
|
|
6654
|
+
getOutwardAxisOption({
|
|
6655
|
+
value: point.x,
|
|
6656
|
+
min: chipBounds.minX,
|
|
6657
|
+
max: chipBounds.maxX,
|
|
6658
|
+
center: chipBounds.centerX,
|
|
6659
|
+
positiveOrientation: "x+",
|
|
6660
|
+
negativeOrientation: "x-"
|
|
6661
|
+
})
|
|
6662
|
+
);
|
|
6722
6663
|
return options;
|
|
6723
6664
|
};
|
|
6724
6665
|
var getOutwardAxisOption = (params) => {
|
|
@@ -6796,6 +6737,22 @@ var roundDistance = (distance3) => Number(distance3.toFixed(6));
|
|
|
6796
6737
|
var dedupeOrientations = (orientations) => [
|
|
6797
6738
|
...new Set(orientations)
|
|
6798
6739
|
];
|
|
6740
|
+
var normalizeFacingDirection = (value) => {
|
|
6741
|
+
switch (value) {
|
|
6742
|
+
case "x+":
|
|
6743
|
+
case "+x":
|
|
6744
|
+
return "x+";
|
|
6745
|
+
case "x-":
|
|
6746
|
+
case "-x":
|
|
6747
|
+
return "x-";
|
|
6748
|
+
case "y+":
|
|
6749
|
+
case "+y":
|
|
6750
|
+
return "y+";
|
|
6751
|
+
case "y-":
|
|
6752
|
+
case "-y":
|
|
6753
|
+
return "y-";
|
|
6754
|
+
}
|
|
6755
|
+
};
|
|
6799
6756
|
var dedupeStrings = (values) => [
|
|
6800
6757
|
...new Set(values.filter((value) => value !== void 0))
|
|
6801
6758
|
];
|
|
@@ -6808,7 +6765,7 @@ var visualizeTraceAnchoredNetLabelOverlapSolver = (state) => {
|
|
|
6808
6765
|
const graphics = visualizeInputProblem(state.inputProblem);
|
|
6809
6766
|
ensureGraphicsArrays3(graphics);
|
|
6810
6767
|
drawTraces4(graphics, state.traces);
|
|
6811
|
-
drawNetLabels4(graphics, state.outputNetLabelPlacements);
|
|
6768
|
+
drawNetLabels4(graphics, state.inputProblem, state.outputNetLabelPlacements);
|
|
6812
6769
|
if (!state.solved) {
|
|
6813
6770
|
drawCurrentOverlap2(graphics, state);
|
|
6814
6771
|
drawCurrentCandidates4(graphics, state.currentCandidateResults);
|
|
@@ -6823,7 +6780,7 @@ var drawTraces4 = (graphics, traces) => {
|
|
|
6823
6780
|
});
|
|
6824
6781
|
}
|
|
6825
6782
|
};
|
|
6826
|
-
var drawNetLabels4 = (graphics, labels) => {
|
|
6783
|
+
var drawNetLabels4 = (graphics, inputProblem, labels) => {
|
|
6827
6784
|
for (const label of labels) {
|
|
6828
6785
|
graphics.rects.push({
|
|
6829
6786
|
center: label.center,
|
|
@@ -6831,8 +6788,7 @@ var drawNetLabels4 = (graphics, labels) => {
|
|
|
6831
6788
|
height: label.height,
|
|
6832
6789
|
fill: getColorFromString(label.globalConnNetId, 0.35),
|
|
6833
6790
|
strokeColor: getColorFromString(label.globalConnNetId, 0.9),
|
|
6834
|
-
label:
|
|
6835
|
-
globalConnNetId: ${label.globalConnNetId}`
|
|
6791
|
+
label: getNetLabelVisualizationLabel(inputProblem, label)
|
|
6836
6792
|
});
|
|
6837
6793
|
graphics.points.push({
|
|
6838
6794
|
x: label.anchorPoint.x,
|
|
@@ -6858,7 +6814,8 @@ var drawCurrentOverlap2 = (graphics, state) => {
|
|
|
6858
6814
|
fill: "rgba(255, 0, 0, 0.2)",
|
|
6859
6815
|
strokeColor: CANDIDATE_REJECTED_COLOR4,
|
|
6860
6816
|
label: `netlabel overlap target
|
|
6861
|
-
${label.netId ?? label.globalConnNetId}
|
|
6817
|
+
${label.netId ?? label.globalConnNetId}
|
|
6818
|
+
${getAvailableOrientationText(state.inputProblem, label)}`
|
|
6862
6819
|
});
|
|
6863
6820
|
}
|
|
6864
6821
|
};
|
|
@@ -6874,7 +6831,9 @@ var drawCurrentCandidates4 = (graphics, candidates) => {
|
|
|
6874
6831
|
strokeDash: candidate.selected ? void 0 : "4 2",
|
|
6875
6832
|
label: `${candidate.selected ? "selected" : candidate.status} netlabel overlap candidate
|
|
6876
6833
|
trace: ${candidate.traceId}
|
|
6877
|
-
distance: ${candidate.
|
|
6834
|
+
path distance: ${candidate.pathDistance.toFixed(3)}
|
|
6835
|
+
orientation: ${candidate.orientation}
|
|
6836
|
+
distance from original: ${candidate.distanceFromOriginal.toFixed(3)}`
|
|
6878
6837
|
});
|
|
6879
6838
|
graphics.points.push({
|
|
6880
6839
|
...candidate.anchorPoint,
|
|
@@ -6891,6 +6850,24 @@ var ensureGraphicsArrays3 = (graphics) => {
|
|
|
6891
6850
|
if (!graphics.circles) graphics.circles = [];
|
|
6892
6851
|
if (!graphics.texts) graphics.texts = [];
|
|
6893
6852
|
};
|
|
6853
|
+
var getAvailableOrientationText = (inputProblem, label) => {
|
|
6854
|
+
const orientations = getAvailableOrientationsForLabel(inputProblem, label);
|
|
6855
|
+
return `available orientations: ${orientations?.join(", ") ?? "any"}`;
|
|
6856
|
+
};
|
|
6857
|
+
var getNetLabelVisualizationLabel = (inputProblem, label) => [
|
|
6858
|
+
`netId: ${label.netId}`,
|
|
6859
|
+
`globalConnNetId: ${label.globalConnNetId}`,
|
|
6860
|
+
getAvailableOrientationText(inputProblem, label)
|
|
6861
|
+
].join("\n");
|
|
6862
|
+
var getAvailableOrientationsForLabel = (inputProblem, label) => {
|
|
6863
|
+
const availableOrientations = inputProblem.availableNetLabelOrientations ?? {};
|
|
6864
|
+
for (const netId of [label.netId, label.globalConnNetId]) {
|
|
6865
|
+
if (netId && Object.hasOwn(availableOrientations, netId)) {
|
|
6866
|
+
return availableOrientations[netId];
|
|
6867
|
+
}
|
|
6868
|
+
}
|
|
6869
|
+
return void 0;
|
|
6870
|
+
};
|
|
6894
6871
|
|
|
6895
6872
|
// lib/solvers/TraceAnchoredNetLabelOverlapSolver/TraceAnchoredNetLabelOverlapSolver.ts
|
|
6896
6873
|
var TraceAnchoredNetLabelOverlapSolver = class extends BaseSolver {
|
|
@@ -7039,9 +7016,7 @@ var TraceAnchoredNetLabelOverlapSolver = class extends BaseSolver {
|
|
|
7039
7016
|
})
|
|
7040
7017
|
);
|
|
7041
7018
|
}
|
|
7042
|
-
return candidates
|
|
7043
|
-
(a, b) => a.distanceFromOriginal - b.distanceFromOriginal || a.pathDistance - b.pathDistance
|
|
7044
|
-
);
|
|
7019
|
+
return candidates;
|
|
7045
7020
|
}
|
|
7046
7021
|
getCandidateStatus(candidate, labelIndex) {
|
|
7047
7022
|
const bounds = getLabelBounds(candidate);
|
|
@@ -7065,7 +7040,10 @@ var TraceAnchoredNetLabelOverlapSolver = class extends BaseSolver {
|
|
|
7065
7040
|
}
|
|
7066
7041
|
intersectsAnyChip(bounds) {
|
|
7067
7042
|
return this.inputProblem.chips.some(
|
|
7068
|
-
(chip) =>
|
|
7043
|
+
(chip) => rectsTouchOrOverlap(
|
|
7044
|
+
bounds,
|
|
7045
|
+
getRectBounds(chip.center, chip.width, chip.height)
|
|
7046
|
+
)
|
|
7069
7047
|
);
|
|
7070
7048
|
}
|
|
7071
7049
|
intersectsAnyOtherLabel(bounds, labelIndex) {
|
|
@@ -7424,6 +7402,7 @@ var SchematicTracePipelineSolver = class extends BaseSolver {
|
|
|
7424
7402
|
circles: visualizations.flatMap((v) => v.circles || []),
|
|
7425
7403
|
texts: visualizations.flatMap((v) => v.texts || [])
|
|
7426
7404
|
};
|
|
7405
|
+
colorAvailableNetOrientationLabels(finalGraphics, this.inputProblem);
|
|
7427
7406
|
return finalGraphics;
|
|
7428
7407
|
}
|
|
7429
7408
|
/**
|
|
@@ -100,7 +100,7 @@ export class AvailableNetOrientationSolver extends BaseSolver {
|
|
|
100
100
|
const indices: number[] = []
|
|
101
101
|
|
|
102
102
|
for (let i = 0; i < this.outputNetLabelPlacements.length; i++) {
|
|
103
|
-
if (this.shouldProcessLabel(this.outputNetLabelPlacements[i]
|
|
103
|
+
if (this.shouldProcessLabel(this.outputNetLabelPlacements[i]!)) {
|
|
104
104
|
indices.push(i)
|
|
105
105
|
}
|
|
106
106
|
}
|
|
@@ -108,14 +108,9 @@ export class AvailableNetOrientationSolver extends BaseSolver {
|
|
|
108
108
|
return indices
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
-
private shouldProcessLabel(label: NetLabelPlacement
|
|
111
|
+
private shouldProcessLabel(label: NetLabelPlacement) {
|
|
112
112
|
const orientations = this.getAvailableOrientations(label)
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
return !(
|
|
116
|
-
orientations.includes(label.orientation) &&
|
|
117
|
-
this.isLabelPlacementValid(label, labelIndex)
|
|
118
|
-
)
|
|
113
|
+
return orientations.length > 0 && !orientations.includes(label.orientation)
|
|
119
114
|
}
|
|
120
115
|
|
|
121
116
|
private processLabel(labelIndex: number) {
|
|
@@ -441,27 +436,6 @@ export class AvailableNetOrientationSolver extends BaseSolver {
|
|
|
441
436
|
)?.netLabelWidth
|
|
442
437
|
}
|
|
443
438
|
|
|
444
|
-
private isLabelPlacementValid(label: NetLabelPlacement, labelIndex: number) {
|
|
445
|
-
return this.isCandidateValidWithOffset(
|
|
446
|
-
{
|
|
447
|
-
orientation: label.orientation,
|
|
448
|
-
anchorPoint: label.anchorPoint,
|
|
449
|
-
center: label.center,
|
|
450
|
-
width: label.width,
|
|
451
|
-
height: label.height,
|
|
452
|
-
},
|
|
453
|
-
labelIndex,
|
|
454
|
-
)
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
private isCandidateValidWithOffset(
|
|
458
|
-
candidate: CandidateLabel,
|
|
459
|
-
labelIndex: number,
|
|
460
|
-
) {
|
|
461
|
-
const bounds = this.getOffsetCollisionBounds(candidate)
|
|
462
|
-
return this.getBoundsStatus(bounds, labelIndex) === "valid"
|
|
463
|
-
}
|
|
464
|
-
|
|
465
439
|
private getCandidateStatus(
|
|
466
440
|
candidate: CandidateLabel,
|
|
467
441
|
label: NetLabelPlacement,
|
|
@@ -505,16 +479,6 @@ export class AvailableNetOrientationSolver extends BaseSolver {
|
|
|
505
479
|
return "valid"
|
|
506
480
|
}
|
|
507
481
|
|
|
508
|
-
private getOffsetCollisionBounds(candidate: CandidateLabel) {
|
|
509
|
-
const direction = dir(candidate.orientation)
|
|
510
|
-
const collisionTestOffset = 1e-4
|
|
511
|
-
const testCenter = {
|
|
512
|
-
x: candidate.center.x + direction.x * collisionTestOffset,
|
|
513
|
-
y: candidate.center.y + direction.y * collisionTestOffset,
|
|
514
|
-
}
|
|
515
|
-
return getRectBounds(testCenter, candidate.width, candidate.height)
|
|
516
|
-
}
|
|
517
|
-
|
|
518
482
|
private intersectsAnyOtherNetLabel(bounds: Bounds, labelIndex: number) {
|
|
519
483
|
for (let i = 0; i < this.outputNetLabelPlacements.length; i++) {
|
|
520
484
|
if (i === labelIndex) continue
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
} from "../SchematicTraceLinesSolver/SchematicTraceLinesSolver"
|
|
14
14
|
import { TraceOverlapShiftSolver } from "../TraceOverlapShiftSolver/TraceOverlapShiftSolver"
|
|
15
15
|
import { NetLabelPlacementSolver } from "../NetLabelPlacementSolver/NetLabelPlacementSolver"
|
|
16
|
+
import { colorAvailableNetOrientationLabels } from "./colorAvailableNetOrientationLabels"
|
|
16
17
|
import { visualizeInputProblem } from "./visualizeInputProblem"
|
|
17
18
|
import { TraceLabelOverlapAvoidanceSolver } from "../TraceLabelOverlapAvoidanceSolver/TraceLabelOverlapAvoidanceSolver"
|
|
18
19
|
import { correctPinsInsideChips } from "./correctPinsInsideChip"
|
|
@@ -403,6 +404,7 @@ export class SchematicTracePipelineSolver extends BaseSolver {
|
|
|
403
404
|
circles: visualizations.flatMap((v) => v.circles || []),
|
|
404
405
|
texts: visualizations.flatMap((v) => v.texts || []),
|
|
405
406
|
}
|
|
407
|
+
colorAvailableNetOrientationLabels(finalGraphics, this.inputProblem)
|
|
406
408
|
return finalGraphics
|
|
407
409
|
}
|
|
408
410
|
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { GraphicsObject } from "graphics-debug"
|
|
2
|
+
import type { InputProblem } from "lib/types/InputProblem"
|
|
3
|
+
|
|
4
|
+
const AVAILABLE_Y_PLUS_COLOR = "#ef4444"
|
|
5
|
+
const AVAILABLE_Y_MINUS_COLOR = "#000000"
|
|
6
|
+
const AVAILABLE_ORIENTATION_FILL_ALPHA = "66"
|
|
7
|
+
|
|
8
|
+
export const colorAvailableNetOrientationLabels = (
|
|
9
|
+
graphicsObject: GraphicsObject,
|
|
10
|
+
inputProblem: InputProblem,
|
|
11
|
+
) => {
|
|
12
|
+
const availableOrientations = inputProblem.availableNetLabelOrientations
|
|
13
|
+
if (!availableOrientations) return
|
|
14
|
+
|
|
15
|
+
for (const rect of graphicsObject.rects ?? []) {
|
|
16
|
+
const orientations = getAvailableOrientationsForRect(
|
|
17
|
+
rect.label,
|
|
18
|
+
availableOrientations,
|
|
19
|
+
)
|
|
20
|
+
if (!orientations) continue
|
|
21
|
+
|
|
22
|
+
const hasYPlus = orientations.includes("y+")
|
|
23
|
+
const hasYMinus = orientations.includes("y-")
|
|
24
|
+
if (hasYPlus === hasYMinus) continue
|
|
25
|
+
|
|
26
|
+
const color = hasYPlus ? AVAILABLE_Y_PLUS_COLOR : AVAILABLE_Y_MINUS_COLOR
|
|
27
|
+
|
|
28
|
+
rect.fill = `${color}${AVAILABLE_ORIENTATION_FILL_ALPHA}`
|
|
29
|
+
rect.stroke = color
|
|
30
|
+
rect.color = color
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const getAvailableOrientationsForRect = (
|
|
35
|
+
label: string | undefined,
|
|
36
|
+
availableOrientations: InputProblem["availableNetLabelOrientations"],
|
|
37
|
+
) => {
|
|
38
|
+
for (const netId of getNetIdsFromRectLabel(label)) {
|
|
39
|
+
if (Object.hasOwn(availableOrientations, netId)) {
|
|
40
|
+
return availableOrientations[netId]
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return undefined
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const getNetIdsFromRectLabel = (label: string | undefined) => {
|
|
48
|
+
if (!label) return []
|
|
49
|
+
|
|
50
|
+
return [
|
|
51
|
+
label.match(/^netId: (.+)$/m)?.[1],
|
|
52
|
+
label.match(/^globalConnNetId: (.+)$/m)?.[1],
|
|
53
|
+
].filter((netId): netId is string => Boolean(netId && netId !== "undefined"))
|
|
54
|
+
}
|
package/lib/solvers/TraceAnchoredNetLabelOverlapSolver/TraceAnchoredNetLabelOverlapSolver.ts
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
getLabelBounds,
|
|
10
10
|
getTraceLocationsForPoint,
|
|
11
11
|
rectsOverlap,
|
|
12
|
+
rectsTouchOrOverlap,
|
|
12
13
|
traceCrossesBoundsInterior,
|
|
13
14
|
} from "./geometry"
|
|
14
15
|
import type {
|
|
@@ -217,11 +218,7 @@ export class TraceAnchoredNetLabelOverlapSolver extends BaseSolver {
|
|
|
217
218
|
)
|
|
218
219
|
}
|
|
219
220
|
|
|
220
|
-
return candidates
|
|
221
|
-
(a, b) =>
|
|
222
|
-
a.distanceFromOriginal - b.distanceFromOriginal ||
|
|
223
|
-
a.pathDistance - b.pathDistance,
|
|
224
|
-
)
|
|
221
|
+
return candidates
|
|
225
222
|
}
|
|
226
223
|
|
|
227
224
|
private getCandidateStatus(
|
|
@@ -256,7 +253,10 @@ export class TraceAnchoredNetLabelOverlapSolver extends BaseSolver {
|
|
|
256
253
|
|
|
257
254
|
private intersectsAnyChip(bounds: Bounds) {
|
|
258
255
|
return this.inputProblem.chips.some((chip) =>
|
|
259
|
-
|
|
256
|
+
rectsTouchOrOverlap(
|
|
257
|
+
bounds,
|
|
258
|
+
getRectBounds(chip.center, chip.width, chip.height),
|
|
259
|
+
),
|
|
260
260
|
)
|
|
261
261
|
}
|
|
262
262
|
|