@tscircuit/schematic-trace-solver 0.0.129 → 0.0.131
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 +7 -0
- package/dist/index.js +219 -13
- package/lib/solvers/AvailableNetOrientationSolver/AvailableNetOrientationSolver.ts +290 -12
- package/lib/solvers/LongDistancePairSolver/LongDistancePairSolver.ts +23 -2
- package/package.json +1 -1
- package/site/bug-reports/bug-report-20260811T075142Z.page.tsx +4 -0
- package/tests/bug-reports/bug-report-20260706T220324Z/__snapshots__/bug-report-20260706T220324Z.snap.svg +34 -22
- package/tests/bug-reports/bug-report-20260707T134549Z/__snapshots__/bug-report-20260707T134549Z.snap.svg +5 -3
- package/tests/bug-reports/bug-report-20260721T221026Z/__snapshots__/bug-report-20260721T221026Z.snap.svg +305 -303
- package/tests/bug-reports/bug-report-20260804T095800Z/__snapshots__/bug-report-20260804T095800Z.snap.svg +5 -3
- package/tests/bug-reports/bug-report-20260811T075142Z/__snapshots__/bug-report-20260811T075142Z.snap.svg +74 -0
- package/tests/bug-reports/bug-report-20260811T075142Z/bug-report-20260811T075142Z.json +194 -0
- package/tests/bug-reports/bug-report-20260811T075142Z/bug-report-20260811T075142Z.test.ts +131 -0
- package/tests/examples/__snapshots__/example10.snap.svg +20 -16
- package/tests/examples/__snapshots__/example31.snap.svg +8 -6
- package/tests/examples/__snapshots__/example33.snap.svg +32 -30
- package/tests/examples/__snapshots__/example46.snap.svg +5 -3
- package/tests/examples/__snapshots__/example48.snap.svg +25 -23
- package/tests/examples/__snapshots__/example50.snap.svg +32 -30
- package/tests/repros/__snapshots__/repro-atmega328p-fault-pullup.snap.svg +48 -46
- package/tests/repros/__snapshots__/repro-board-589-regulator-section.snap.svg +69 -0
- package/tests/repros/__snapshots__/repro-bq24074-battery-charger.snap.svg +7 -5
- package/tests/repros/__snapshots__/repro-missing-trace-netlabel.snap.svg +24 -18
- package/tests/repros/__snapshots__/repro-usb-power-vbus-label-detour.snap.svg +467 -0
- package/tests/repros/__snapshots__/repro51-overlap-junction-crossing.snap.svg +25 -23
- package/tests/repros/__snapshots__/small-variant-resistor-facing-direction.snap.svg +46 -44
- package/tests/repros/assets/repro-board-589-regulator-section.input.json +270 -0
- package/tests/repros/assets/repro-usb-power-vbus-label-detour.input.json +2382 -0
- package/tests/repros/repro-board-589-regulator-section.test.ts +16 -0
- package/tests/repros/repro-max-msp-pair-distance-fallback.test.ts +45 -0
- package/tests/repros/repro-missing-trace-netlabel.test.ts +9 -11
- package/tests/repros/repro-usb-power-vbus-label-detour.test.ts +16 -0
- package/tests/repros/rotated-components-rail-label.test.ts +5 -11
package/dist/index.d.ts
CHANGED
|
@@ -621,6 +621,7 @@ declare class LongDistancePairSolver extends BaseSolver {
|
|
|
621
621
|
private netConnMap;
|
|
622
622
|
private newlyConnectedPinIds;
|
|
623
623
|
private allSolvedTraces;
|
|
624
|
+
private maxMspPairDistance;
|
|
624
625
|
constructor(params: {
|
|
625
626
|
inputProblem: InputProblem;
|
|
626
627
|
alreadySolvedTraces: SolvedTracePath[];
|
|
@@ -778,6 +779,7 @@ declare class AvailableNetOrientationSolver extends BaseSolver {
|
|
|
778
779
|
currentLabelIndex: number | null;
|
|
779
780
|
currentLabel: NetLabelPlacement | null;
|
|
780
781
|
currentCandidateResults: EvaluatedCandidate[];
|
|
782
|
+
private crowdedPortOnlyLabelIndices;
|
|
781
783
|
blockedStandaloneLabelIndex: number | null;
|
|
782
784
|
blockedStandaloneLabelTargetAnchorX: number | null;
|
|
783
785
|
private traceMap;
|
|
@@ -792,13 +794,16 @@ declare class AvailableNetOrientationSolver extends BaseSolver {
|
|
|
792
794
|
netLabelPlacements: NetLabelPlacement[];
|
|
793
795
|
};
|
|
794
796
|
private getProcessableLabelIndices;
|
|
797
|
+
private sortCrowdedTopBankByPin;
|
|
795
798
|
private shouldProcessLabel;
|
|
799
|
+
private getCrowdedPortOnlyLabelIndices;
|
|
796
800
|
private processLabel;
|
|
797
801
|
private applyCandidate;
|
|
798
802
|
private addConnectorTrace;
|
|
799
803
|
private finish;
|
|
800
804
|
private setCurrentLabel;
|
|
801
805
|
private findCorrectedCandidate;
|
|
806
|
+
private findValidCrowdedTopVerticalFanoutCandidate;
|
|
802
807
|
private hasTraceContinuingInOrientation;
|
|
803
808
|
private findValidRotatedCandidate;
|
|
804
809
|
private findValidTraceAnchorCandidate;
|
|
@@ -841,10 +846,12 @@ declare class AvailableNetOrientationSolver extends BaseSolver {
|
|
|
841
846
|
private hasOppositeVerticalRailOnSameChipSide;
|
|
842
847
|
private getSingleChipSideForNetConnection;
|
|
843
848
|
private isPortOnlyLabel;
|
|
849
|
+
private shouldIgnorePendingCrowdedLabel;
|
|
844
850
|
private intersectsAnyOtherNetLabel;
|
|
845
851
|
private sharesChipBoundary;
|
|
846
852
|
private getChipSideForPoint;
|
|
847
853
|
private getPerpendicularOutwardDirection;
|
|
854
|
+
private getChipOutwardDirection;
|
|
848
855
|
private getContainingChipSide;
|
|
849
856
|
private getOutsideChipSide;
|
|
850
857
|
private getNearestChipSide;
|
package/dist/index.js
CHANGED
|
@@ -4618,6 +4618,7 @@ var NEAREST_NEIGHBOR_COUNT = 3;
|
|
|
4618
4618
|
var distance3 = (p1, p2) => {
|
|
4619
4619
|
return Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2));
|
|
4620
4620
|
};
|
|
4621
|
+
var manhattanDistance = (p1, p2) => Math.abs(p1.x - p2.x) + Math.abs(p1.y - p2.y);
|
|
4621
4622
|
var LongDistancePairSolver = class extends BaseSolver {
|
|
4622
4623
|
constructor(params) {
|
|
4623
4624
|
super();
|
|
@@ -4625,6 +4626,7 @@ var LongDistancePairSolver = class extends BaseSolver {
|
|
|
4625
4626
|
const { inputProblem, primaryMspConnectionPairs, alreadySolvedTraces } = this.params;
|
|
4626
4627
|
this.inputProblem = inputProblem;
|
|
4627
4628
|
this.allSolvedTraces = [...alreadySolvedTraces];
|
|
4629
|
+
this.maxMspPairDistance = inputProblem.maxMspPairDistance ?? DEFAULT_MAX_MSP_PAIR_DISTANCE;
|
|
4628
4630
|
const primaryConnectedPinIds = /* @__PURE__ */ new Set();
|
|
4629
4631
|
for (const pair of primaryMspConnectionPairs) {
|
|
4630
4632
|
primaryConnectedPinIds.add(pair.pins[0].pinId);
|
|
@@ -4660,6 +4662,12 @@ var LongDistancePairSolver = class extends BaseSolver {
|
|
|
4660
4662
|
const neighbors = allPinIdsInNet.filter((otherPinId) => otherPinId !== unconnectedPinId).flatMap((otherPinId) => {
|
|
4661
4663
|
const targetPin = pinMap.get(otherPinId);
|
|
4662
4664
|
if (!targetPin) return [];
|
|
4665
|
+
const isNamedTwoPinConnection = inputProblem.netConnections.some(
|
|
4666
|
+
(connection) => connection.pinIds.length === 2 && connection.pinIds.includes(sourcePin.pinId) && connection.pinIds.includes(targetPin.pinId)
|
|
4667
|
+
);
|
|
4668
|
+
if (isNamedTwoPinConnection && manhattanDistance(sourcePin, targetPin) > this.maxMspPairDistance) {
|
|
4669
|
+
return [];
|
|
4670
|
+
}
|
|
4663
4671
|
return [
|
|
4664
4672
|
{
|
|
4665
4673
|
pin: targetPin,
|
|
@@ -4694,6 +4702,7 @@ var LongDistancePairSolver = class extends BaseSolver {
|
|
|
4694
4702
|
netConnMap;
|
|
4695
4703
|
newlyConnectedPinIds = /* @__PURE__ */ new Set();
|
|
4696
4704
|
allSolvedTraces = [];
|
|
4705
|
+
maxMspPairDistance;
|
|
4697
4706
|
getConstructorParams() {
|
|
4698
4707
|
return this.params;
|
|
4699
4708
|
}
|
|
@@ -8053,6 +8062,7 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
8053
8062
|
currentLabelIndex = null;
|
|
8054
8063
|
currentLabel = null;
|
|
8055
8064
|
currentCandidateResults = [];
|
|
8065
|
+
crowdedPortOnlyLabelIndices = /* @__PURE__ */ new Set();
|
|
8056
8066
|
blockedStandaloneLabelIndex = null;
|
|
8057
8067
|
blockedStandaloneLabelTargetAnchorX = null;
|
|
8058
8068
|
traceMap;
|
|
@@ -8071,6 +8081,7 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
8071
8081
|
this.pinMap = getPinMap(params.inputProblem);
|
|
8072
8082
|
this.chipObstacleSpatialIndex = params.inputProblem._chipObstacleSpatialIndex ?? new ChipObstacleSpatialIndex(params.inputProblem.chips);
|
|
8073
8083
|
this.maxSearchDistance = getMaxSearchDistance(params.inputProblem);
|
|
8084
|
+
this.crowdedPortOnlyLabelIndices = this.getCrowdedPortOnlyLabelIndices();
|
|
8074
8085
|
this.queuedLabelIndices = this.getProcessableLabelIndices();
|
|
8075
8086
|
this.setCurrentLabel(this.queuedLabelIndices[0] ?? null);
|
|
8076
8087
|
}
|
|
@@ -8098,10 +8109,11 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
8098
8109
|
getProcessableLabelIndices() {
|
|
8099
8110
|
const indices = [];
|
|
8100
8111
|
for (let i = 0; i < this.outputNetLabelPlacements.length; i++) {
|
|
8101
|
-
if (this.shouldProcessLabel(this.outputNetLabelPlacements[i])) {
|
|
8112
|
+
if (this.shouldProcessLabel(this.outputNetLabelPlacements[i], i)) {
|
|
8102
8113
|
indices.push(i);
|
|
8103
8114
|
}
|
|
8104
8115
|
}
|
|
8116
|
+
this.sortCrowdedTopBankByPin(indices);
|
|
8105
8117
|
const blockedStandaloneLabelIndex = indices.find((index) => {
|
|
8106
8118
|
const label = this.outputNetLabelPlacements[index];
|
|
8107
8119
|
const orientations = this.getAvailableOrientations(label);
|
|
@@ -8150,9 +8162,87 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
8150
8162
|
}
|
|
8151
8163
|
return indices;
|
|
8152
8164
|
}
|
|
8153
|
-
|
|
8165
|
+
sortCrowdedTopBankByPin(indices) {
|
|
8166
|
+
const slotsByChip = /* @__PURE__ */ new Map();
|
|
8167
|
+
for (let slot = 0; slot < indices.length; slot++) {
|
|
8168
|
+
const labelIndex = indices[slot];
|
|
8169
|
+
if (!this.crowdedPortOnlyLabelIndices.has(labelIndex)) continue;
|
|
8170
|
+
const label = this.outputNetLabelPlacements[labelIndex];
|
|
8171
|
+
if (this.getChipSideForPoint(label.anchorPoint) !== "top") continue;
|
|
8172
|
+
const pin = this.pinMap[label.pinIds[0]];
|
|
8173
|
+
if (!pin) continue;
|
|
8174
|
+
const slots = slotsByChip.get(pin.chipId) ?? [];
|
|
8175
|
+
slots.push(slot);
|
|
8176
|
+
slotsByChip.set(pin.chipId, slots);
|
|
8177
|
+
}
|
|
8178
|
+
for (const slots of slotsByChip.values()) {
|
|
8179
|
+
const labelIndices = slots.map((slot) => indices[slot]).sort((a, b) => {
|
|
8180
|
+
const aPin = this.pinMap[this.outputNetLabelPlacements[a].pinIds[0]];
|
|
8181
|
+
const bPin = this.pinMap[this.outputNetLabelPlacements[b].pinIds[0]];
|
|
8182
|
+
return aPin.x - bPin.x;
|
|
8183
|
+
});
|
|
8184
|
+
for (let position = 0; position < slots.length; position++) {
|
|
8185
|
+
indices[slots[position]] = labelIndices[position];
|
|
8186
|
+
}
|
|
8187
|
+
}
|
|
8188
|
+
}
|
|
8189
|
+
shouldProcessLabel(label, labelIndex) {
|
|
8154
8190
|
const orientations = this.getAvailableOrientations(label);
|
|
8155
|
-
|
|
8191
|
+
if (orientations.length === 0) return false;
|
|
8192
|
+
if (!orientations.includes(label.orientation)) return true;
|
|
8193
|
+
if (!this.crowdedPortOnlyLabelIndices.has(labelIndex)) return false;
|
|
8194
|
+
const bounds = getRectBounds(label.center, label.width, label.height);
|
|
8195
|
+
return this.outputNetLabelPlacements.some((otherLabel, otherIndex) => {
|
|
8196
|
+
if (otherIndex === labelIndex) return false;
|
|
8197
|
+
if (otherLabel.globalConnNetId === label.globalConnNetId) return false;
|
|
8198
|
+
return rectsOverlap2(
|
|
8199
|
+
bounds,
|
|
8200
|
+
getRectBounds(otherLabel.center, otherLabel.width, otherLabel.height)
|
|
8201
|
+
);
|
|
8202
|
+
});
|
|
8203
|
+
}
|
|
8204
|
+
getCrowdedPortOnlyLabelIndices() {
|
|
8205
|
+
const labelIndicesByChipAndSide = /* @__PURE__ */ new Map();
|
|
8206
|
+
for (let i = 0; i < this.outputNetLabelPlacements.length; i++) {
|
|
8207
|
+
const label = this.outputNetLabelPlacements[i];
|
|
8208
|
+
if (!this.isPortOnlyLabel(label)) continue;
|
|
8209
|
+
if (!this.isStandaloneSinglePinNetLabel(label)) continue;
|
|
8210
|
+
if (this.getAvailableOrientations(label).length === 0) continue;
|
|
8211
|
+
const pin = this.pinMap[label.pinIds[0]];
|
|
8212
|
+
if (!pin) continue;
|
|
8213
|
+
const chipSide = this.getChipSideForPoint(label.anchorPoint);
|
|
8214
|
+
if (!chipSide) continue;
|
|
8215
|
+
const labelIndicesBySide = labelIndicesByChipAndSide.get(pin.chipId) ?? /* @__PURE__ */ new Map();
|
|
8216
|
+
const labelIndices = labelIndicesBySide.get(chipSide) ?? [];
|
|
8217
|
+
labelIndices.push(i);
|
|
8218
|
+
labelIndicesBySide.set(chipSide, labelIndices);
|
|
8219
|
+
labelIndicesByChipAndSide.set(pin.chipId, labelIndicesBySide);
|
|
8220
|
+
}
|
|
8221
|
+
const crowdedIndices = /* @__PURE__ */ new Set();
|
|
8222
|
+
for (const labelIndicesBySide of labelIndicesByChipAndSide.values()) {
|
|
8223
|
+
for (const labelIndices of labelIndicesBySide.values()) {
|
|
8224
|
+
const hasWrongOrientation = labelIndices.some((index) => {
|
|
8225
|
+
const label = this.outputNetLabelPlacements[index];
|
|
8226
|
+
return !this.getAvailableOrientations(label).includes(
|
|
8227
|
+
label.orientation
|
|
8228
|
+
);
|
|
8229
|
+
});
|
|
8230
|
+
const hasOverlap = labelIndices.some((index, position) => {
|
|
8231
|
+
const label = this.outputNetLabelPlacements[index];
|
|
8232
|
+
const bounds = getRectBounds(label.center, label.width, label.height);
|
|
8233
|
+
return labelIndices.slice(position + 1).some((otherIndex) => {
|
|
8234
|
+
const other = this.outputNetLabelPlacements[otherIndex];
|
|
8235
|
+
return rectsOverlap2(
|
|
8236
|
+
bounds,
|
|
8237
|
+
getRectBounds(other.center, other.width, other.height)
|
|
8238
|
+
);
|
|
8239
|
+
});
|
|
8240
|
+
});
|
|
8241
|
+
if (!hasWrongOrientation || !hasOverlap) continue;
|
|
8242
|
+
for (const index of labelIndices) crowdedIndices.add(index);
|
|
8243
|
+
}
|
|
8244
|
+
}
|
|
8245
|
+
return crowdedIndices;
|
|
8156
8246
|
}
|
|
8157
8247
|
processLabel(labelIndex) {
|
|
8158
8248
|
const label = this.outputNetLabelPlacements[labelIndex];
|
|
@@ -8171,7 +8261,11 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
8171
8261
|
}
|
|
8172
8262
|
addConnectorTrace(label, candidate, labelIndex) {
|
|
8173
8263
|
if (candidate.phase === "trace-anchor") return;
|
|
8174
|
-
const tracePath = this.getCandidateConnectorTrace(
|
|
8264
|
+
const tracePath = this.getCandidateConnectorTrace(
|
|
8265
|
+
label,
|
|
8266
|
+
candidate,
|
|
8267
|
+
labelIndex
|
|
8268
|
+
);
|
|
8175
8269
|
if (tracePath.length < 2) return;
|
|
8176
8270
|
const mspPairId = `available-net-orientation-${labelIndex}-${label.netId ?? label.globalConnNetId}`;
|
|
8177
8271
|
const connectorTrace = {
|
|
@@ -8200,6 +8294,14 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
8200
8294
|
findCorrectedCandidate(label, labelIndex) {
|
|
8201
8295
|
const orientations = this.getAvailableOrientations(label);
|
|
8202
8296
|
const requiredOrientation = orientations[0];
|
|
8297
|
+
if (this.crowdedPortOnlyLabelIndices.has(labelIndex) && this.getChipSideForPoint(label.anchorPoint) === "top" && isYOrientation(requiredOrientation)) {
|
|
8298
|
+
const topFanoutCandidate = this.findValidCrowdedTopVerticalFanoutCandidate(
|
|
8299
|
+
label,
|
|
8300
|
+
labelIndex,
|
|
8301
|
+
requiredOrientation
|
|
8302
|
+
);
|
|
8303
|
+
if (topFanoutCandidate) return topFanoutCandidate;
|
|
8304
|
+
}
|
|
8203
8305
|
const netConnection = this.inputProblem.netConnections.find(
|
|
8204
8306
|
(connection) => connection.netId === label.netId
|
|
8205
8307
|
);
|
|
@@ -8254,6 +8356,77 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
8254
8356
|
labelIndex
|
|
8255
8357
|
);
|
|
8256
8358
|
}
|
|
8359
|
+
findValidCrowdedTopVerticalFanoutCandidate(label, labelIndex, orientation) {
|
|
8360
|
+
const pin = this.pinMap[label.pinIds[0]];
|
|
8361
|
+
const chip = pin ? this.chipObstacleSpatialIndex.chips.find(
|
|
8362
|
+
(candidate) => candidate.chipId === pin.chipId
|
|
8363
|
+
) : void 0;
|
|
8364
|
+
if (!chip) return null;
|
|
8365
|
+
const { width, height } = getDimsForOrientation({
|
|
8366
|
+
orientation,
|
|
8367
|
+
netLabelWidth: this.getNetLabelWidth(label),
|
|
8368
|
+
netLabelHeight: this.getNetLabelHeight(label)
|
|
8369
|
+
});
|
|
8370
|
+
const nextPinToRight = this.outputNetLabelPlacements.map((otherLabel, index) => ({
|
|
8371
|
+
index,
|
|
8372
|
+
pin: this.pinMap[otherLabel.pinIds[0]]
|
|
8373
|
+
})).filter(
|
|
8374
|
+
({ index, pin: otherPin }) => this.crowdedPortOnlyLabelIndices.has(index) && otherPin?.chipId === pin.chipId && otherPin.x > pin.x + EPS11
|
|
8375
|
+
).sort((a, b) => a.pin.x - b.pin.x)[0]?.pin;
|
|
8376
|
+
if (orientation === "y-" && nextPinToRight) return null;
|
|
8377
|
+
const anchorX = orientation === "y-" ? Math.max(
|
|
8378
|
+
label.anchorPoint.x + LABEL_SEARCH_STEP,
|
|
8379
|
+
chip.bounds.maxX + width / 2 + LABEL_TRACE_CLEARANCE2
|
|
8380
|
+
) : Math.min(
|
|
8381
|
+
label.anchorPoint.x,
|
|
8382
|
+
(nextPinToRight?.x ?? chip.bounds.maxX) - LABEL_SEARCH_STEP - width / 2
|
|
8383
|
+
);
|
|
8384
|
+
let highestPlacedLabelY = chip.bounds.maxY;
|
|
8385
|
+
let lowestUpFacingLabelY = Number.POSITIVE_INFINITY;
|
|
8386
|
+
let highestUpFacingLabelY = Number.NEGATIVE_INFINITY;
|
|
8387
|
+
for (let index = 0; index < this.outputNetLabelPlacements.length; index++) {
|
|
8388
|
+
if (index === labelIndex) continue;
|
|
8389
|
+
if (!this.crowdedPortOnlyLabelIndices.has(index)) continue;
|
|
8390
|
+
if (this.queuedLabelIndices.includes(index)) continue;
|
|
8391
|
+
const placedLabel = this.outputNetLabelPlacements[index];
|
|
8392
|
+
const placedBounds = getRectBounds(
|
|
8393
|
+
placedLabel.center,
|
|
8394
|
+
placedLabel.width,
|
|
8395
|
+
placedLabel.height
|
|
8396
|
+
);
|
|
8397
|
+
highestPlacedLabelY = Math.max(highestPlacedLabelY, placedBounds.maxY);
|
|
8398
|
+
if (placedLabel.orientation !== "y+") continue;
|
|
8399
|
+
lowestUpFacingLabelY = Math.min(lowestUpFacingLabelY, placedBounds.minY);
|
|
8400
|
+
highestUpFacingLabelY = Math.max(highestUpFacingLabelY, placedBounds.maxY);
|
|
8401
|
+
}
|
|
8402
|
+
const stackedAnchorY = highestPlacedLabelY + LABEL_SEARCH_STEP + (orientation === "y-" ? height : 0);
|
|
8403
|
+
const hasUpFacingStack = Number.isFinite(lowestUpFacingLabelY) && Number.isFinite(highestUpFacingLabelY);
|
|
8404
|
+
const centeredAnchorY = hasUpFacingStack ? (lowestUpFacingLabelY + highestUpFacingLabelY) / 2 : stackedAnchorY;
|
|
8405
|
+
const anchorYs = orientation === "y-" ? [centeredAnchorY, stackedAnchorY] : [stackedAnchorY];
|
|
8406
|
+
for (const anchorY of anchorYs) {
|
|
8407
|
+
if (anchorY - label.anchorPoint.y > this.maxSearchDistance + EPS11) {
|
|
8408
|
+
continue;
|
|
8409
|
+
}
|
|
8410
|
+
const candidate = this.createCandidate(
|
|
8411
|
+
label,
|
|
8412
|
+
{ x: anchorX, y: anchorY },
|
|
8413
|
+
orientation
|
|
8414
|
+
);
|
|
8415
|
+
const result = this.evaluateCandidate(
|
|
8416
|
+
candidate,
|
|
8417
|
+
label,
|
|
8418
|
+
labelIndex,
|
|
8419
|
+
"lateral-shift",
|
|
8420
|
+
anchorY - label.anchorPoint.y,
|
|
8421
|
+
anchorX - label.anchorPoint.x
|
|
8422
|
+
);
|
|
8423
|
+
this.currentCandidateResults.push(result);
|
|
8424
|
+
if (result.status !== "valid") continue;
|
|
8425
|
+
result.selected = true;
|
|
8426
|
+
return result;
|
|
8427
|
+
}
|
|
8428
|
+
return null;
|
|
8429
|
+
}
|
|
8257
8430
|
hasTraceContinuingInOrientation(label, orientation) {
|
|
8258
8431
|
const direction = dir(orientation);
|
|
8259
8432
|
return Object.values(this.traceMap).some((trace) => {
|
|
@@ -8521,12 +8694,22 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
8521
8694
|
})
|
|
8522
8695
|
};
|
|
8523
8696
|
}
|
|
8524
|
-
getCandidateConnectorTrace(label, candidate) {
|
|
8697
|
+
getCandidateConnectorTrace(label, candidate, labelIndex) {
|
|
8698
|
+
if (this.crowdedPortOnlyLabelIndices.has(labelIndex) && this.getChipSideForPoint(label.anchorPoint) === "top" && isYOrientation(candidate.orientation)) {
|
|
8699
|
+
return simplifyOrthogonalPath([
|
|
8700
|
+
label.anchorPoint,
|
|
8701
|
+
{ x: label.anchorPoint.x, y: candidate.anchorPoint.y },
|
|
8702
|
+
candidate.anchorPoint
|
|
8703
|
+
]);
|
|
8704
|
+
}
|
|
8525
8705
|
if (candidate.phase === "lateral-shift") {
|
|
8526
|
-
const
|
|
8706
|
+
const chipOutwardDir = this.crowdedPortOnlyLabelIndices.has(labelIndex) ? this.getChipOutwardDirection(label.anchorPoint) : (() => {
|
|
8707
|
+
const orientDir = dir(candidate.orientation);
|
|
8708
|
+
return { x: -orientDir.x, y: -orientDir.y };
|
|
8709
|
+
})();
|
|
8527
8710
|
const kickedSource = {
|
|
8528
|
-
x: label.anchorPoint.x
|
|
8529
|
-
y: label.anchorPoint.y
|
|
8711
|
+
x: label.anchorPoint.x + chipOutwardDir.x * LABEL_SEARCH_STEP,
|
|
8712
|
+
y: label.anchorPoint.y + chipOutwardDir.y * LABEL_SEARCH_STEP
|
|
8530
8713
|
};
|
|
8531
8714
|
return simplifyOrthogonalPath([
|
|
8532
8715
|
label.anchorPoint,
|
|
@@ -8741,11 +8924,15 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
8741
8924
|
});
|
|
8742
8925
|
if (nonChipBoundsStatus !== "valid") return nonChipBoundsStatus;
|
|
8743
8926
|
}
|
|
8744
|
-
const connectorTrace = this.getCandidateConnectorTrace(
|
|
8745
|
-
|
|
8746
|
-
|
|
8747
|
-
|
|
8748
|
-
|
|
8927
|
+
const connectorTrace = this.getCandidateConnectorTrace(
|
|
8928
|
+
label,
|
|
8929
|
+
{
|
|
8930
|
+
anchorPoint: candidate.anchorPoint,
|
|
8931
|
+
orientation: candidate.orientation,
|
|
8932
|
+
phase
|
|
8933
|
+
},
|
|
8934
|
+
labelIndex
|
|
8935
|
+
);
|
|
8749
8936
|
for (const chip of this.chipObstacleSpatialIndex.chips) {
|
|
8750
8937
|
if (tracePathCrossesAnyBounds(connectorTrace, chip.bounds)) {
|
|
8751
8938
|
return "chip-collision";
|
|
@@ -8753,6 +8940,7 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
8753
8940
|
}
|
|
8754
8941
|
for (let i = 0; i < this.outputNetLabelPlacements.length; i++) {
|
|
8755
8942
|
if (i === labelIndex) continue;
|
|
8943
|
+
if (this.shouldIgnorePendingCrowdedLabel(labelIndex, i)) continue;
|
|
8756
8944
|
const otherLabel = this.outputNetLabelPlacements[i];
|
|
8757
8945
|
if (tracePathIntersectsBounds(
|
|
8758
8946
|
connectorTrace,
|
|
@@ -8891,9 +9079,13 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
8891
9079
|
isPortOnlyLabel(label) {
|
|
8892
9080
|
return label.mspConnectionPairIds.length === 0;
|
|
8893
9081
|
}
|
|
9082
|
+
shouldIgnorePendingCrowdedLabel(labelIndex, otherLabelIndex) {
|
|
9083
|
+
return this.crowdedPortOnlyLabelIndices.has(labelIndex) && this.crowdedPortOnlyLabelIndices.has(otherLabelIndex) && this.queuedLabelIndices.includes(otherLabelIndex);
|
|
9084
|
+
}
|
|
8894
9085
|
intersectsAnyOtherNetLabel(bounds, labelIndex) {
|
|
8895
9086
|
for (let i = 0; i < this.outputNetLabelPlacements.length; i++) {
|
|
8896
9087
|
if (i === labelIndex) continue;
|
|
9088
|
+
if (this.shouldIgnorePendingCrowdedLabel(labelIndex, i)) continue;
|
|
8897
9089
|
const label = this.outputNetLabelPlacements[i];
|
|
8898
9090
|
const otherBounds = getRectBounds(label.center, label.width, label.height);
|
|
8899
9091
|
if (i === this.blockedStandaloneLabelIndex && isYOrientation(label.orientation)) {
|
|
@@ -8951,6 +9143,20 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
8951
9143
|
}
|
|
8952
9144
|
return { x: 0, y: 0 };
|
|
8953
9145
|
}
|
|
9146
|
+
getChipOutwardDirection(point) {
|
|
9147
|
+
switch (this.getChipSideForPoint(point)) {
|
|
9148
|
+
case "left":
|
|
9149
|
+
return { x: -1, y: 0 };
|
|
9150
|
+
case "right":
|
|
9151
|
+
return { x: 1, y: 0 };
|
|
9152
|
+
case "bottom":
|
|
9153
|
+
return { x: 0, y: -1 };
|
|
9154
|
+
case "top":
|
|
9155
|
+
return { x: 0, y: 1 };
|
|
9156
|
+
default:
|
|
9157
|
+
return { x: 0, y: 0 };
|
|
9158
|
+
}
|
|
9159
|
+
}
|
|
8954
9160
|
getContainingChipSide(point) {
|
|
8955
9161
|
let nearestSide = null;
|
|
8956
9162
|
let nearestDistance = Number.POSITIVE_INFINITY;
|