@tscircuit/schematic-trace-solver 0.0.179 → 0.0.181
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 +2 -2
- package/dist/index.js +88 -11
- package/lib/solvers/AvailableNetOrientationSolver/AvailableNetOrientationSolver.ts +63 -4
- package/lib/solvers/AvailableNetOrientationSolver/traces.ts +36 -0
- package/lib/solvers/AvailableNetOrientationSolver/types.ts +1 -0
- package/lib/solvers/SameNetJunctionAlignmentSolver/alignSameNetJunctions.ts +29 -11
- package/package.json +1 -1
- package/tests/bug-reports/bug-report-20260706T213649Z/__snapshots__/bug-report-20260706T213649Z.snap.svg +2 -114
- package/tests/bug-reports/bug-report-20260706T213649Z/bug-report-20260706T213649Z.json +1 -0
- package/tests/bug-reports/bug-report-20260706T220324Z/__snapshots__/bug-report-20260706T220324Z.snap.svg +3 -94
- package/tests/bug-reports/bug-report-20260706T220324Z/bug-report-20260706T220324Z.json +1 -0
- package/tests/bug-reports/bug-report-20260707T092615Z/__snapshots__/bug-report-20260707T092615Z.snap.svg +533 -578
- package/tests/bug-reports/bug-report-20260707T092615Z/bug-report-20260707T092615Z.json +1 -0
- package/tests/bug-reports/bug-report-20260707T134549Z/__snapshots__/bug-report-20260707T134549Z.snap.svg +2 -37
- package/tests/bug-reports/bug-report-20260707T134549Z/bug-report-20260707T134549Z.json +1 -0
- package/tests/bug-reports/bug-report-20260707T134722Z/__snapshots__/bug-report-20260707T134722Z.snap.svg +4 -25
- package/tests/bug-reports/bug-report-20260707T134722Z/bug-report-20260707T134722Z.json +1 -0
- package/tests/bug-reports/bug-report-20260707T140410Z/__snapshots__/bug-report-20260707T140410Z.snap.svg +1 -50
- package/tests/bug-reports/bug-report-20260707T140410Z/bug-report-20260707T140410Z.json +1 -0
- package/tests/bug-reports/bug-report-20260707T141025Z/__snapshots__/bug-report-20260707T141025Z.snap.svg +1 -15
- package/tests/bug-reports/bug-report-20260707T141025Z/bug-report-20260707T141025Z.json +1 -0
- package/tests/bug-reports/bug-report-20260707T141421Z/__snapshots__/bug-report-20260707T141421Z.snap.svg +5 -33
- package/tests/bug-reports/bug-report-20260707T141421Z/bug-report-20260707T141421Z.json +1 -0
- package/tests/bug-reports/bug-report-20260707T230831Z/__snapshots__/bug-report-20260707T230831Z.snap.svg +1 -15
- package/tests/bug-reports/bug-report-20260707T230831Z/bug-report-20260707T230831Z.json +1 -0
- package/tests/bug-reports/bug-report-20260708T055430Z/__snapshots__/bug-report-20260708T055430Z.snap.svg +65 -79
- package/tests/bug-reports/bug-report-20260708T055430Z/bug-report-20260708T055430Z.json +1 -0
- package/tests/bug-reports/bug-report-20260708T095725Z/__snapshots__/bug-report-20260708T095725Z.snap.svg +1 -15
- package/tests/bug-reports/bug-report-20260708T095725Z/bug-report-20260708T095725Z.json +1 -0
- package/tests/bug-reports/bug-report-20260716T144856Z/__snapshots__/bug-report-20260716T144856Z.snap.svg +1 -43
- package/tests/bug-reports/bug-report-20260716T144856Z/bug-report-20260716T144856Z.json +1 -0
- package/tests/bug-reports/bug-report-20260717T022934Z/__snapshots__/bug-report-20260717T022934Z.snap.svg +2 -30
- package/tests/bug-reports/bug-report-20260717T022934Z/bug-report-20260717T022934Z.json +1 -0
- package/tests/bug-reports/bug-report-20260717T031704Z/__snapshots__/bug-report-20260717T031704Z.snap.svg +1 -8
- package/tests/bug-reports/bug-report-20260717T031704Z/bug-report-20260717T031704Z.json +1 -0
- package/tests/bug-reports/bug-report-20260721T221026Z/__snapshots__/bug-report-20260721T221026Z.snap.svg +1 -92
- package/tests/bug-reports/bug-report-20260721T221026Z/bug-report-20260721T221026Z.json +1 -0
- package/tests/bug-reports/bug-report-20260728T144234Z/__snapshots__/bug-report-20260728T144234Z.snap.svg +1 -29
- package/tests/bug-reports/bug-report-20260728T144234Z/bug-report-20260728T144234Z.json +1 -0
- package/tests/bug-reports/bug-report-20260728T225606Z/__snapshots__/bug-report-20260728T225606Z.snap.svg +1 -22
- package/tests/bug-reports/bug-report-20260728T225606Z/bug-report-20260728T225606Z.json +1 -0
- package/tests/bug-reports/bug-report-20260730T061837Z/__snapshots__/bug-report-20260730T061837Z.snap.svg +1 -8
- package/tests/bug-reports/bug-report-20260730T061837Z/bug-report-20260730T061837Z.json +1 -0
- package/tests/bug-reports/bug-report-20260804T095800Z/__snapshots__/bug-report-20260804T095800Z.snap.svg +1 -36
- package/tests/bug-reports/bug-report-20260804T095800Z/bug-report-20260804T095800Z.json +1 -0
- package/tests/bug-reports/bug-report-20260804T171919Z/__snapshots__/bug-report-20260804T171919Z.snap.svg +2 -121
- package/tests/bug-reports/bug-report-20260804T171919Z/bug-report-20260804T171919Z.json +1 -0
- package/tests/bug-reports/bug-report-20260804T225912Z/__snapshots__/bug-report-20260804T225912Z.snap.svg +1 -8
- package/tests/bug-reports/bug-report-20260804T225912Z/bug-report-20260804T225912Z.json +1 -0
- package/tests/bug-reports/bug-report-20260805T061316Z/__snapshots__/bug-report-20260805T061316Z.snap.svg +1 -15
- package/tests/bug-reports/bug-report-20260805T061316Z/bug-report-20260805T061316Z.json +1 -0
- package/tests/bug-reports/bug-report-20260806T061548Z/__snapshots__/bug-report-20260806T061548Z.snap.svg +1 -15
- package/tests/bug-reports/bug-report-20260806T061548Z/bug-report-20260806T061548Z.json +1 -0
- package/tests/bug-reports/bug-report-20260806T093501Z/__snapshots__/bug-report-20260806T093501Z.snap.svg +1 -22
- package/tests/bug-reports/bug-report-20260806T093501Z/bug-report-20260806T093501Z.json +1 -0
- package/tests/bug-reports/bug-report-20260811T075142Z/__snapshots__/bug-report-20260811T075142Z.snap.svg +1 -8
- package/tests/bug-reports/bug-report-20260811T075142Z/bug-report-20260811T075142Z.json +1 -0
- package/tests/bug-reports/bug-report-20260815T073240Z/__snapshots__/bug-report-20260815T073240Z.snap.svg +1 -22
- package/tests/bug-reports/bug-report-20260815T073240Z/bug-report-20260815T073240Z.json +1 -0
- package/tests/bug-reports/bug-report-20260819T091818Z/__snapshots__/bug-report-20260819T091818Z.snap.svg +1 -15
- package/tests/bug-reports/bug-report-20260819T091818Z/bug-report-20260819T091818Z.json +1 -0
- package/tests/bug-reports/bug-report-20260825T103621Z/__snapshots__/bug-report-20260825T103621Z.snap.svg +1 -29
- package/tests/bug-reports/bug-report-20260825T103621Z/bug-report-20260825T103621Z.json +1 -0
- package/tests/bug-reports/bug-report-20260826T072956Z/__snapshots__/bug-report-20260826T072956Z.snap.svg +31 -95
- package/tests/bug-reports/bug-report-20260826T072956Z/bug-report-20260826T072956Z.json +1 -0
- package/tests/repros/__snapshots__/board-1273-trace-overlap-cycle.snap.svg +1 -113
- package/tests/repros/__snapshots__/board-15984-same-net-junction.snap.svg +1 -29
- package/tests/repros/__snapshots__/board1096-usb-label-overlap-iteration.snap.svg +64 -56
- package/tests/repros/__snapshots__/bugreport-001-gnd-overlap.snap.svg +1 -15
- package/tests/repros/__snapshots__/netlabel-connector-through-rail-label.snap.svg +1 -22
- package/tests/repros/__snapshots__/repro-atmega328p-missing-gnd-netlabel.snap.svg +185 -186
- package/tests/repros/__snapshots__/repro-board-589-regulator-section.snap.svg +1 -15
- package/tests/repros/__snapshots__/repro-board-648-esp12f-section.snap.svg +1 -15
- package/tests/repros/__snapshots__/repro-board-8090-power-section.snap.svg +126 -0
- package/tests/repros/__snapshots__/repro-bq24074-battery-charger.snap.svg +1 -29
- package/tests/repros/__snapshots__/repro-bq25895-cross-net-trace-overlap.snap.svg +1 -8
- package/tests/repros/__snapshots__/repro-cc2340r5.snap.svg +1 -15
- package/tests/repros/__snapshots__/repro-example35-minimize-trace-crossing.snap.svg +1 -8
- package/tests/repros/__snapshots__/repro-hub-usb-sheet.snap.svg +545 -0
- package/tests/repros/__snapshots__/repro-ina237-current-monitor.snap.svg +1 -22
- package/tests/repros/__snapshots__/repro-isolated-rs485-isow7841.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-mcp73831-charger-traces.snap.svg +131 -0
- package/tests/repros/__snapshots__/repro-missing-trace-netlabel.snap.svg +1 -15
- package/tests/repros/__snapshots__/repro-mouse-switch-ground-unnecessary-jog.snap.svg +83 -0
- package/tests/repros/__snapshots__/repro-mspm0l1306-capacitor-symmetry.snap.svg +1 -29
- package/tests/repros/__snapshots__/repro-netlabel-overlap-trace.snap.svg +1 -8
- package/tests/repros/__snapshots__/repro-nrf52810-clock-routing.snap.svg +1 -29
- package/tests/repros/__snapshots__/repro-pmp11282-isolated-dcdc.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-powerbank-3v-system-power.snap.svg +1 -29
- package/tests/repros/__snapshots__/repro-rf1-unnecessary-dogleg.snap.svg +72 -0
- package/tests/repros/__snapshots__/repro-rp2040-gamepad-trace-alignment.snap.svg +1 -8
- package/tests/repros/__snapshots__/repro-rp2040-usb-cc2-ground-overlap.snap.svg +1 -8
- package/tests/repros/__snapshots__/repro-smartwatch-power-sheet.snap.svg +4 -4
- package/tests/repros/__snapshots__/repro-tps61222-trace-intersection.snap.svg +1 -8
- package/tests/repros/__snapshots__/repro-usb-power-vbus-label-detour.snap.svg +991 -1091
- package/tests/repros/__snapshots__/repro130-bq27441-fuel-gauge-trace-through-c1.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro161-power-section-autolayout.snap.svg +1 -15
- package/tests/repros/__snapshots__/repro48-555-timer-vcc-rail-label.snap.svg +1 -22
- package/tests/repros/__snapshots__/repro51-overlap-junction-crossing.snap.svg +1 -15
- package/tests/repros/__snapshots__/small-variant-resistor-facing-direction.snap.svg +65 -79
- package/tests/repros/__snapshots__/trace-overlap-box-resistor.snap.svg +1 -8
- package/tests/repros/assets/board-1273-trace-overlap-cycle.input.json +1 -0
- package/tests/repros/assets/board-15984-schematic-trace-input.json +1 -0
- package/tests/repros/assets/bugreport-001-gnd-overlap.input.json +1 -0
- package/tests/repros/assets/repro-atmega328p-fault-pullup.input.json +1 -0
- package/tests/repros/assets/repro-atmega328p-missing-gnd-netlabel.input.json +1 -0
- package/tests/repros/assets/repro-board-589-regulator-section.input.json +1 -0
- package/tests/repros/assets/repro-board-648-esp12f-section.input.json +1 -0
- package/tests/repros/assets/repro-board-8090-power-section.input.json +322 -0
- package/tests/repros/assets/repro-bq24074-battery-charger.input.json +1 -0
- package/tests/repros/assets/repro-bq25895-cross-net-trace-overlap.input.json +1 -0
- package/tests/repros/assets/repro-cc2340r5.input.json +1 -0
- package/tests/repros/assets/repro-example35-minimize-trace-crossing.input.json +1 -0
- package/tests/repros/assets/repro-hub-usb-sheet.input.json +3967 -0
- package/tests/repros/assets/repro-ina237-current-monitor.input.json +1 -0
- package/tests/repros/assets/repro-mcp73831-charger-traces.input.json +256 -0
- package/tests/repros/assets/repro-missing-trace-netlabel.input.json +1 -0
- package/tests/repros/assets/repro-mouse-switch-ground-unnecessary-jog.input.json +158 -0
- package/tests/repros/assets/repro-mspm0l1306-capacitor-symmetry.input.json +1 -0
- package/tests/repros/assets/repro-netlabel-connector-through-label.input.json +1 -0
- package/tests/repros/assets/repro-netlabel-overlap-trace.input.json +1 -0
- package/tests/repros/assets/repro-nrf52810-clock-routing.input.json +1 -0
- package/tests/repros/assets/repro-powerbank-3v-system-power.input.json +1 -0
- package/tests/repros/assets/repro-rf1-unnecessary-dogleg.input.json +90 -0
- package/tests/repros/assets/repro-rp2040-gamepad-trace-alignment.input.json +1 -0
- package/tests/repros/assets/repro-rp2040-usb-cc2-ground-overlap.input.json +1 -0
- package/tests/repros/assets/repro-tps61222-trace-intersection.input.json +1 -0
- package/tests/repros/assets/repro-usb-power-vbus-label-detour.input.json +1 -0
- package/tests/repros/assets/repro126-trace-overlap-box-resistor.input.json +1 -0
- package/tests/repros/assets/repro161-power-section-autolayout.input.json +1 -0
- package/tests/repros/assets/repro48-555-timer-vcc-rail-label.input.json +1 -0
- package/tests/repros/assets/repro51-overlap-junction-crossing.input.json +1 -0
- package/tests/repros/assets/small-variant-resistor-facing-direction.input.json +1 -0
- package/tests/repros/board1096-usb-label-overlap-iteration.json +1 -0
- package/tests/repros/board1096-usb-label-overlap-iteration.test.ts +1 -1
- package/tests/repros/repro-battery-management-bq24073.test.ts +17 -0
- package/tests/repros/repro-board-8090-power-section.test.ts +18 -0
- package/tests/repros/repro-hub-usb-sheet.test.ts +56 -0
- package/tests/repros/repro-mcp73831-charger-traces.test.ts +16 -0
- package/tests/repros/repro-mouse-switch-ground-unnecessary-jog.test.ts +15 -0
- package/tests/repros/repro-rf1-unnecessary-dogleg.test.ts +15 -0
- package/tests/repros/repro-smartwatch-power-sheet.test.ts +31 -5
package/dist/index.d.ts
CHANGED
|
@@ -831,7 +831,7 @@ type CandidateLabel = {
|
|
|
831
831
|
height: number;
|
|
832
832
|
};
|
|
833
833
|
type CandidateStatus$2 = "valid" | "chip-collision" | "text-collision" | "trace-collision" | "trace-clearance-violation" | "netlabel-collision";
|
|
834
|
-
type CandidatePhase = "rotate" | "trace-anchor" | "connected-rail-shift" | "outward-trace-anchor" | "shift" | "lateral-shift";
|
|
834
|
+
type CandidatePhase = "rotate" | "trace-anchor" | "connected-rail-shift" | "downward-ground-rail-extension" | "outward-trace-anchor" | "shift" | "lateral-shift";
|
|
835
835
|
type EvaluatedCandidate = CandidateLabel & {
|
|
836
836
|
status: CandidateStatus$2;
|
|
837
837
|
selected: boolean;
|
|
@@ -916,7 +916,7 @@ declare class AvailableNetOrientationSolver extends BaseSolver {
|
|
|
916
916
|
private createCandidate;
|
|
917
917
|
private getNetLabelHeight;
|
|
918
918
|
private getCandidateStatus;
|
|
919
|
-
private
|
|
919
|
+
private isAcceptableConnectedChipBoundaryOverlap;
|
|
920
920
|
private staysOutsideConnectedPinRow;
|
|
921
921
|
private getBoundsStatus;
|
|
922
922
|
private isTraceTooCloseToLabel;
|
package/dist/index.js
CHANGED
|
@@ -7709,6 +7709,27 @@ var TraceCleanupSolver = class extends BaseSolver {
|
|
|
7709
7709
|
};
|
|
7710
7710
|
|
|
7711
7711
|
// lib/solvers/AvailableNetOrientationSolver/traces.ts
|
|
7712
|
+
var extendVerticalTracePathAtInteriorPoint = ({
|
|
7713
|
+
tracePath,
|
|
7714
|
+
sourcePoint,
|
|
7715
|
+
extensionEndPoint
|
|
7716
|
+
}) => {
|
|
7717
|
+
const sourceIndex = tracePath.findIndex(
|
|
7718
|
+
(point) => pointsEqual(point, sourcePoint)
|
|
7719
|
+
);
|
|
7720
|
+
if (sourceIndex <= 0 || sourceIndex >= tracePath.length - 1) return null;
|
|
7721
|
+
const extensionDirectionY = extensionEndPoint.y - sourcePoint.y;
|
|
7722
|
+
const adjacentIndex = [sourceIndex - 1, sourceIndex + 1].find((index) => {
|
|
7723
|
+
const point = tracePath[index];
|
|
7724
|
+
return isVertical2(point, sourcePoint) && (point.y - sourcePoint.y) * extensionDirectionY < 0;
|
|
7725
|
+
});
|
|
7726
|
+
if (adjacentIndex === void 0) return null;
|
|
7727
|
+
return tracePath.toSpliced(
|
|
7728
|
+
Math.max(sourceIndex, adjacentIndex),
|
|
7729
|
+
0,
|
|
7730
|
+
extensionEndPoint
|
|
7731
|
+
);
|
|
7732
|
+
};
|
|
7712
7733
|
var getPinMap = (inputProblem) => {
|
|
7713
7734
|
const pinMap = {};
|
|
7714
7735
|
for (const chip of inputProblem.chips) {
|
|
@@ -9028,6 +9049,7 @@ function getPaddedBounds(bounds, padding) {
|
|
|
9028
9049
|
|
|
9029
9050
|
// lib/solvers/AvailableNetOrientationSolver/AvailableNetOrientationSolver.ts
|
|
9030
9051
|
var LABEL_TRACE_CLEARANCE2 = 0.1;
|
|
9052
|
+
var MIN_DOWNWARD_GROUND_RAIL_EXTENSION = 0.2;
|
|
9031
9053
|
var CONNECTED_PIN_ROW_OVERLAP_TOLERANCE = 0.1;
|
|
9032
9054
|
var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
9033
9055
|
inputProblem;
|
|
@@ -9267,6 +9289,20 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
9267
9289
|
}
|
|
9268
9290
|
addConnectorTrace(label, candidate, labelIndex) {
|
|
9269
9291
|
if (candidate.phase === "trace-anchor") return;
|
|
9292
|
+
if (candidate.phase === "downward-ground-rail-extension") {
|
|
9293
|
+
for (const mspPairId2 of label.mspConnectionPairIds) {
|
|
9294
|
+
const hostTrace = this.traceMap[mspPairId2];
|
|
9295
|
+
if (!hostTrace) continue;
|
|
9296
|
+
const extendedTracePath = extendVerticalTracePathAtInteriorPoint({
|
|
9297
|
+
tracePath: hostTrace.tracePath,
|
|
9298
|
+
sourcePoint: label.anchorPoint,
|
|
9299
|
+
extensionEndPoint: candidate.anchorPoint
|
|
9300
|
+
});
|
|
9301
|
+
if (!extendedTracePath) continue;
|
|
9302
|
+
hostTrace.tracePath = extendedTracePath;
|
|
9303
|
+
return;
|
|
9304
|
+
}
|
|
9305
|
+
}
|
|
9270
9306
|
const tracePath = this.getCandidateConnectorTrace(
|
|
9271
9307
|
label,
|
|
9272
9308
|
candidate,
|
|
@@ -9313,6 +9349,7 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
9313
9349
|
(connection) => connection.netId === label.netId
|
|
9314
9350
|
);
|
|
9315
9351
|
const isTwoPinNet = netConnection?.pinIds.length === 2;
|
|
9352
|
+
const isDownwardGroundRail = netConnection?.isGround && isXOrientation(label.orientation) && orientations.length === 1 && requiredOrientation === "y-" && this.hasTraceContinuingInOrientation(label, "y+");
|
|
9316
9353
|
const isDistanceSplitVerticalRail = (netConnection?.pinIds.length ?? 0) > 2 && isYOrientation(requiredOrientation) && this.hasPortOnlyLabelOnSameNet(label);
|
|
9317
9354
|
const textBlockedMultiPinRailTraces = this.getTextBlockedMultiPinRailTraces(
|
|
9318
9355
|
label,
|
|
@@ -9370,6 +9407,26 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
9370
9407
|
labelIndex,
|
|
9371
9408
|
orientations
|
|
9372
9409
|
);
|
|
9410
|
+
const rotatedCandidateNeedsLateralBranch = rotatedCandidate !== null && Math.abs(rotatedCandidate.anchorPoint.x - label.anchorPoint.x) > EPS13;
|
|
9411
|
+
if (isDownwardGroundRail && rotatedCandidateNeedsLateralBranch) {
|
|
9412
|
+
const downwardRailCandidate = this.findValidCandidateInShiftColumn({
|
|
9413
|
+
label,
|
|
9414
|
+
labelIndex,
|
|
9415
|
+
orientation: requiredOrientation,
|
|
9416
|
+
direction: dir(requiredOrientation),
|
|
9417
|
+
baseAnchor: label.anchorPoint,
|
|
9418
|
+
maxSearchDistance: this.getSearchDistanceLimit(
|
|
9419
|
+
label,
|
|
9420
|
+
requiredOrientation
|
|
9421
|
+
),
|
|
9422
|
+
outwardDistance: 0,
|
|
9423
|
+
phase: "downward-ground-rail-extension",
|
|
9424
|
+
stopOnTraceCollision: false,
|
|
9425
|
+
connectorSource: label.anchorPoint,
|
|
9426
|
+
startDistance: MIN_DOWNWARD_GROUND_RAIL_EXTENSION
|
|
9427
|
+
});
|
|
9428
|
+
if (downwardRailCandidate) return downwardRailCandidate;
|
|
9429
|
+
}
|
|
9373
9430
|
if (rotatedCandidate) return rotatedCandidate;
|
|
9374
9431
|
const traceAnchorCandidate = this.findValidTraceAnchorCandidate(
|
|
9375
9432
|
label,
|
|
@@ -10096,7 +10153,12 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
10096
10153
|
label
|
|
10097
10154
|
});
|
|
10098
10155
|
if (boundsStatus !== "valid") {
|
|
10099
|
-
|
|
10156
|
+
const canOverlapConnectedChipBoundary = phase === "trace-anchor" || phase === "connected-rail-shift" || phase === "downward-ground-rail-extension";
|
|
10157
|
+
if (!canOverlapConnectedChipBoundary || boundsStatus !== "chip-collision" || !this.isAcceptableConnectedChipBoundaryOverlap(
|
|
10158
|
+
candidate,
|
|
10159
|
+
label,
|
|
10160
|
+
bounds
|
|
10161
|
+
) || phase === "connected-rail-shift" && !this.staysOutsideConnectedPinRow({ candidate, label, bounds })) {
|
|
10100
10162
|
return boundsStatus;
|
|
10101
10163
|
}
|
|
10102
10164
|
const nonChipBoundsStatus = this.getBoundsStatus({
|
|
@@ -10140,7 +10202,7 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
10140
10202
|
}
|
|
10141
10203
|
return "valid";
|
|
10142
10204
|
}
|
|
10143
|
-
|
|
10205
|
+
isAcceptableConnectedChipBoundaryOverlap(candidate, label, bounds) {
|
|
10144
10206
|
const collidingChips = this.chipObstacleSpatialIndex.getChipsInBounds(bounds);
|
|
10145
10207
|
if (collidingChips.length === 0) return false;
|
|
10146
10208
|
const labelChipIds = new Set(
|
|
@@ -13220,11 +13282,26 @@ var getAlignedSharedEndpointRailPath = ({
|
|
|
13220
13282
|
const donorDeparture = donorPath[1][donorDepartureAxis] - donorPath[0][donorDepartureAxis];
|
|
13221
13283
|
const branchDeparture = branchPath[1][branchDepartureAxis] - branchPath[0][branchDepartureAxis];
|
|
13222
13284
|
if (Math.sign(donorDeparture) !== Math.sign(branchDeparture)) return null;
|
|
13223
|
-
|
|
13224
|
-
|
|
13285
|
+
let railIndex = 1;
|
|
13286
|
+
let donorRailAxis = getSegmentAxis3(donorPath[1], donorPath[2]);
|
|
13287
|
+
let branchRailAxis = getSegmentAxis3(branchPath[1], branchPath[2]);
|
|
13225
13288
|
if (!donorRailAxis || donorRailAxis !== branchRailAxis || donorRailAxis === donorDepartureAxis) {
|
|
13226
13289
|
return null;
|
|
13227
13290
|
}
|
|
13291
|
+
const firstRailsAreAligned = donorRailAxis === "x" && nearlyEqual(donorPath[1].y, branchPath[1].y) || donorRailAxis === "y" && nearlyEqual(donorPath[1].x, branchPath[1].x);
|
|
13292
|
+
if (firstRailsAreAligned) {
|
|
13293
|
+
railIndex++;
|
|
13294
|
+
if (!donorPath[railIndex + 2] || !branchPath[railIndex + 2]) return null;
|
|
13295
|
+
donorRailAxis = getSegmentAxis3(
|
|
13296
|
+
donorPath[railIndex],
|
|
13297
|
+
donorPath[railIndex + 1]
|
|
13298
|
+
);
|
|
13299
|
+
branchRailAxis = getSegmentAxis3(
|
|
13300
|
+
branchPath[railIndex],
|
|
13301
|
+
branchPath[railIndex + 1]
|
|
13302
|
+
);
|
|
13303
|
+
if (!donorRailAxis || donorRailAxis !== branchRailAxis) return null;
|
|
13304
|
+
}
|
|
13228
13305
|
let branchParallelRailCount = 0;
|
|
13229
13306
|
for (let index = 1; index < branchPath.length - 2; index++) {
|
|
13230
13307
|
if (getSegmentAxis3(branchPath[index], branchPath[index + 1]) === branchRailAxis) {
|
|
@@ -13233,25 +13310,25 @@ var getAlignedSharedEndpointRailPath = ({
|
|
|
13233
13310
|
}
|
|
13234
13311
|
if (branchParallelRailCount !== 1) return null;
|
|
13235
13312
|
const railCoordinateAxis = donorRailAxis === "x" ? "y" : "x";
|
|
13236
|
-
const donorCoordinate = donorPath[
|
|
13237
|
-
const branchCoordinate = branchPath[
|
|
13313
|
+
const donorCoordinate = donorPath[railIndex][railCoordinateAxis];
|
|
13314
|
+
const branchCoordinate = branchPath[railIndex][railCoordinateAxis];
|
|
13238
13315
|
const railOffset = Math.abs(donorCoordinate - branchCoordinate);
|
|
13239
13316
|
if (nearlyEqual(donorCoordinate, branchCoordinate) || railOffset > MAX_SHARED_ENDPOINT_RAIL_OFFSET) {
|
|
13240
13317
|
return null;
|
|
13241
13318
|
}
|
|
13242
13319
|
const donorRange = [
|
|
13243
|
-
donorPath[
|
|
13244
|
-
donorPath[
|
|
13320
|
+
donorPath[railIndex][donorRailAxis],
|
|
13321
|
+
donorPath[railIndex + 1][donorRailAxis]
|
|
13245
13322
|
].sort((a, b) => a - b);
|
|
13246
13323
|
const branchRange = [
|
|
13247
|
-
branchPath[
|
|
13248
|
-
branchPath[
|
|
13324
|
+
branchPath[railIndex][branchRailAxis],
|
|
13325
|
+
branchPath[railIndex + 1][branchRailAxis]
|
|
13249
13326
|
].sort((a, b) => a - b);
|
|
13250
13327
|
const railsTouchAfterAlignment = Math.min(donorRange[1], branchRange[1]) >= Math.max(donorRange[0], branchRange[0]) - 1e-6;
|
|
13251
13328
|
if (!railsTouchAfterAlignment) return null;
|
|
13252
13329
|
const candidateFromShared = simplifyPath(
|
|
13253
13330
|
branchPath.map(
|
|
13254
|
-
(point, index) => index ===
|
|
13331
|
+
(point, index) => index === railIndex || index === railIndex + 1 ? { ...point, [railCoordinateAxis]: donorCoordinate } : point
|
|
13255
13332
|
)
|
|
13256
13333
|
);
|
|
13257
13334
|
return branchTrace.pins[0].pinId === sharedPin.pinId ? candidateFromShared : candidateFromShared.reverse();
|
|
@@ -41,7 +41,12 @@ import {
|
|
|
41
41
|
tracePathIntersectsBounds,
|
|
42
42
|
} from "./geometry"
|
|
43
43
|
import { orderRoutedLabelsBeforeOverlappingPortLabels } from "./orderRoutedLabelsBeforeOverlappingPortLabels"
|
|
44
|
-
import {
|
|
44
|
+
import {
|
|
45
|
+
extendVerticalTracePathAtInteriorPoint,
|
|
46
|
+
getPinMap,
|
|
47
|
+
getTracePins,
|
|
48
|
+
toNetLabelPlacementPatch,
|
|
49
|
+
} from "./traces"
|
|
45
50
|
import type {
|
|
46
51
|
AvailableNetOrientationSolverParams,
|
|
47
52
|
Bounds,
|
|
@@ -55,6 +60,7 @@ import { visualizeAvailableNetOrientationSolver } from "./visualize"
|
|
|
55
60
|
import { AvailableNetOrientationObstacleIndex } from "./AvailableNetOrientationObstacleIndex"
|
|
56
61
|
|
|
57
62
|
const LABEL_TRACE_CLEARANCE = 0.1
|
|
63
|
+
const MIN_DOWNWARD_GROUND_RAIL_EXTENSION = 0.2
|
|
58
64
|
const CONNECTED_PIN_ROW_OVERLAP_TOLERANCE = 0.1
|
|
59
65
|
|
|
60
66
|
export class AvailableNetOrientationSolver extends BaseSolver {
|
|
@@ -357,6 +363,21 @@ export class AvailableNetOrientationSolver extends BaseSolver {
|
|
|
357
363
|
) {
|
|
358
364
|
if (candidate.phase === "trace-anchor") return
|
|
359
365
|
|
|
366
|
+
if (candidate.phase === "downward-ground-rail-extension") {
|
|
367
|
+
for (const mspPairId of label.mspConnectionPairIds) {
|
|
368
|
+
const hostTrace = this.traceMap[mspPairId]
|
|
369
|
+
if (!hostTrace) continue
|
|
370
|
+
const extendedTracePath = extendVerticalTracePathAtInteriorPoint({
|
|
371
|
+
tracePath: hostTrace.tracePath,
|
|
372
|
+
sourcePoint: label.anchorPoint,
|
|
373
|
+
extensionEndPoint: candidate.anchorPoint,
|
|
374
|
+
})
|
|
375
|
+
if (!extendedTracePath) continue
|
|
376
|
+
hostTrace.tracePath = extendedTracePath
|
|
377
|
+
return
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
360
381
|
const tracePath = this.getCandidateConnectorTrace(
|
|
361
382
|
label,
|
|
362
383
|
candidate,
|
|
@@ -416,6 +437,12 @@ export class AvailableNetOrientationSolver extends BaseSolver {
|
|
|
416
437
|
(connection) => connection.netId === label.netId,
|
|
417
438
|
)
|
|
418
439
|
const isTwoPinNet = netConnection?.pinIds.length === 2
|
|
440
|
+
const isDownwardGroundRail =
|
|
441
|
+
netConnection?.isGround &&
|
|
442
|
+
isXOrientation(label.orientation) &&
|
|
443
|
+
orientations.length === 1 &&
|
|
444
|
+
requiredOrientation === "y-" &&
|
|
445
|
+
this.hasTraceContinuingInOrientation(label, "y+")
|
|
419
446
|
const isDistanceSplitVerticalRail =
|
|
420
447
|
(netConnection?.pinIds.length ?? 0) > 2 &&
|
|
421
448
|
isYOrientation(requiredOrientation) &&
|
|
@@ -495,6 +522,30 @@ export class AvailableNetOrientationSolver extends BaseSolver {
|
|
|
495
522
|
labelIndex,
|
|
496
523
|
orientations,
|
|
497
524
|
)
|
|
525
|
+
const rotatedCandidateNeedsLateralBranch =
|
|
526
|
+
rotatedCandidate !== null &&
|
|
527
|
+
Math.abs(rotatedCandidate.anchorPoint.x - label.anchorPoint.x) > EPS
|
|
528
|
+
|
|
529
|
+
if (isDownwardGroundRail && rotatedCandidateNeedsLateralBranch) {
|
|
530
|
+
const downwardRailCandidate = this.findValidCandidateInShiftColumn({
|
|
531
|
+
label,
|
|
532
|
+
labelIndex,
|
|
533
|
+
orientation: requiredOrientation,
|
|
534
|
+
direction: dir(requiredOrientation),
|
|
535
|
+
baseAnchor: label.anchorPoint,
|
|
536
|
+
maxSearchDistance: this.getSearchDistanceLimit(
|
|
537
|
+
label,
|
|
538
|
+
requiredOrientation,
|
|
539
|
+
),
|
|
540
|
+
outwardDistance: 0,
|
|
541
|
+
phase: "downward-ground-rail-extension",
|
|
542
|
+
stopOnTraceCollision: false,
|
|
543
|
+
connectorSource: label.anchorPoint,
|
|
544
|
+
startDistance: MIN_DOWNWARD_GROUND_RAIL_EXTENSION,
|
|
545
|
+
})
|
|
546
|
+
if (downwardRailCandidate) return downwardRailCandidate
|
|
547
|
+
}
|
|
548
|
+
|
|
498
549
|
if (rotatedCandidate) return rotatedCandidate
|
|
499
550
|
|
|
500
551
|
const traceAnchorCandidate = this.findValidTraceAnchorCandidate(
|
|
@@ -1525,10 +1576,18 @@ export class AvailableNetOrientationSolver extends BaseSolver {
|
|
|
1525
1576
|
label,
|
|
1526
1577
|
})
|
|
1527
1578
|
if (boundsStatus !== "valid") {
|
|
1579
|
+
const canOverlapConnectedChipBoundary =
|
|
1580
|
+
phase === "trace-anchor" ||
|
|
1581
|
+
phase === "connected-rail-shift" ||
|
|
1582
|
+
phase === "downward-ground-rail-extension"
|
|
1528
1583
|
if (
|
|
1529
|
-
|
|
1584
|
+
!canOverlapConnectedChipBoundary ||
|
|
1530
1585
|
boundsStatus !== "chip-collision" ||
|
|
1531
|
-
!this.
|
|
1586
|
+
!this.isAcceptableConnectedChipBoundaryOverlap(
|
|
1587
|
+
candidate,
|
|
1588
|
+
label,
|
|
1589
|
+
bounds,
|
|
1590
|
+
) ||
|
|
1532
1591
|
(phase === "connected-rail-shift" &&
|
|
1533
1592
|
!this.staysOutsideConnectedPinRow({ candidate, label, bounds }))
|
|
1534
1593
|
) {
|
|
@@ -1587,7 +1646,7 @@ export class AvailableNetOrientationSolver extends BaseSolver {
|
|
|
1587
1646
|
return "valid"
|
|
1588
1647
|
}
|
|
1589
1648
|
|
|
1590
|
-
private
|
|
1649
|
+
private isAcceptableConnectedChipBoundaryOverlap(
|
|
1591
1650
|
candidate: CandidateLabel,
|
|
1592
1651
|
label: NetLabelPlacement,
|
|
1593
1652
|
bounds: Bounds,
|
|
@@ -1,8 +1,44 @@
|
|
|
1
|
+
import type { Point } from "@tscircuit/math-utils"
|
|
1
2
|
import type { NetLabelPlacement } from "lib/solvers/NetLabelPlacementSolver/NetLabelPlacementSolver"
|
|
2
3
|
import type { SolvedTracePath } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceLinesSolver"
|
|
4
|
+
import {
|
|
5
|
+
isVertical,
|
|
6
|
+
pointsEqual,
|
|
7
|
+
} from "lib/solvers/TraceCleanupSolver/sameNetRailAlignment/geometry"
|
|
3
8
|
import type { InputPin, InputProblem } from "lib/types/InputProblem"
|
|
4
9
|
import type { CandidateLabel } from "./types"
|
|
5
10
|
|
|
11
|
+
export const extendVerticalTracePathAtInteriorPoint = ({
|
|
12
|
+
tracePath,
|
|
13
|
+
sourcePoint,
|
|
14
|
+
extensionEndPoint,
|
|
15
|
+
}: {
|
|
16
|
+
tracePath: Point[]
|
|
17
|
+
sourcePoint: Point
|
|
18
|
+
extensionEndPoint: Point
|
|
19
|
+
}) => {
|
|
20
|
+
const sourceIndex = tracePath.findIndex((point) =>
|
|
21
|
+
pointsEqual(point, sourcePoint),
|
|
22
|
+
)
|
|
23
|
+
if (sourceIndex <= 0 || sourceIndex >= tracePath.length - 1) return null
|
|
24
|
+
|
|
25
|
+
const extensionDirectionY = extensionEndPoint.y - sourcePoint.y
|
|
26
|
+
const adjacentIndex = [sourceIndex - 1, sourceIndex + 1].find((index) => {
|
|
27
|
+
const point = tracePath[index]!
|
|
28
|
+
return (
|
|
29
|
+
isVertical(point, sourcePoint) &&
|
|
30
|
+
(point.y - sourcePoint.y) * extensionDirectionY < 0
|
|
31
|
+
)
|
|
32
|
+
})
|
|
33
|
+
if (adjacentIndex === undefined) return null
|
|
34
|
+
|
|
35
|
+
return tracePath.toSpliced(
|
|
36
|
+
Math.max(sourceIndex, adjacentIndex),
|
|
37
|
+
0,
|
|
38
|
+
extensionEndPoint,
|
|
39
|
+
)
|
|
40
|
+
}
|
|
41
|
+
|
|
6
42
|
export const getPinMap = (inputProblem: InputProblem) => {
|
|
7
43
|
const pinMap: Record<string, InputPin & { chipId: string }> = {}
|
|
8
44
|
for (const chip of inputProblem.chips) {
|
|
@@ -375,8 +375,8 @@ const getAlignedParallelPinExitPath = ({
|
|
|
375
375
|
}
|
|
376
376
|
|
|
377
377
|
/**
|
|
378
|
-
* Move the first movable rail of a branch onto the
|
|
379
|
-
* trace leaving the same endpoint. The two
|
|
378
|
+
* Move the first divergent movable rail of a branch onto the matching rail of
|
|
379
|
+
* another trace leaving the same endpoint. The two rail intervals must
|
|
380
380
|
* touch after the move; the caller then verifies that the combined visible
|
|
381
381
|
* trace loses a segment and that the reroute is clear.
|
|
382
382
|
*/
|
|
@@ -419,8 +419,9 @@ const getAlignedSharedEndpointRailPath = ({
|
|
|
419
419
|
branchPath[1]![branchDepartureAxis] - branchPath[0]![branchDepartureAxis]
|
|
420
420
|
if (Math.sign(donorDeparture) !== Math.sign(branchDeparture)) return null
|
|
421
421
|
|
|
422
|
-
|
|
423
|
-
|
|
422
|
+
let railIndex = 1
|
|
423
|
+
let donorRailAxis = getSegmentAxis(donorPath[1]!, donorPath[2]!)
|
|
424
|
+
let branchRailAxis = getSegmentAxis(branchPath[1]!, branchPath[2]!)
|
|
424
425
|
if (
|
|
425
426
|
!donorRailAxis ||
|
|
426
427
|
donorRailAxis !== branchRailAxis ||
|
|
@@ -428,6 +429,23 @@ const getAlignedSharedEndpointRailPath = ({
|
|
|
428
429
|
) {
|
|
429
430
|
return null
|
|
430
431
|
}
|
|
432
|
+
const firstRailsAreAligned =
|
|
433
|
+
(donorRailAxis === "x" && nearlyEqual(donorPath[1]!.y, branchPath[1]!.y)) ||
|
|
434
|
+
(donorRailAxis === "y" && nearlyEqual(donorPath[1]!.x, branchPath[1]!.x))
|
|
435
|
+
// An already-shared rail can lead into the nearby parallel pair to merge.
|
|
436
|
+
if (firstRailsAreAligned) {
|
|
437
|
+
railIndex++
|
|
438
|
+
if (!donorPath[railIndex + 2] || !branchPath[railIndex + 2]) return null
|
|
439
|
+
donorRailAxis = getSegmentAxis(
|
|
440
|
+
donorPath[railIndex]!,
|
|
441
|
+
donorPath[railIndex + 1]!,
|
|
442
|
+
)
|
|
443
|
+
branchRailAxis = getSegmentAxis(
|
|
444
|
+
branchPath[railIndex]!,
|
|
445
|
+
branchPath[railIndex + 1]!,
|
|
446
|
+
)
|
|
447
|
+
if (!donorRailAxis || donorRailAxis !== branchRailAxis) return null
|
|
448
|
+
}
|
|
431
449
|
// A return bus has another rail with this orientation near its far
|
|
432
450
|
// endpoint. Moving only the first rail would partially rewrite a shape that
|
|
433
451
|
// must be evaluated as a whole by the endpoint-bus transformation.
|
|
@@ -443,8 +461,8 @@ const getAlignedSharedEndpointRailPath = ({
|
|
|
443
461
|
if (branchParallelRailCount !== 1) return null
|
|
444
462
|
|
|
445
463
|
const railCoordinateAxis = donorRailAxis === "x" ? "y" : "x"
|
|
446
|
-
const donorCoordinate = donorPath[
|
|
447
|
-
const branchCoordinate = branchPath[
|
|
464
|
+
const donorCoordinate = donorPath[railIndex]![railCoordinateAxis]
|
|
465
|
+
const branchCoordinate = branchPath[railIndex]![railCoordinateAxis]
|
|
448
466
|
const railOffset = Math.abs(donorCoordinate - branchCoordinate)
|
|
449
467
|
if (
|
|
450
468
|
nearlyEqual(donorCoordinate, branchCoordinate) ||
|
|
@@ -454,12 +472,12 @@ const getAlignedSharedEndpointRailPath = ({
|
|
|
454
472
|
}
|
|
455
473
|
|
|
456
474
|
const donorRange = [
|
|
457
|
-
donorPath[
|
|
458
|
-
donorPath[
|
|
475
|
+
donorPath[railIndex]![donorRailAxis],
|
|
476
|
+
donorPath[railIndex + 1]![donorRailAxis],
|
|
459
477
|
].sort((a, b) => a - b)
|
|
460
478
|
const branchRange = [
|
|
461
|
-
branchPath[
|
|
462
|
-
branchPath[
|
|
479
|
+
branchPath[railIndex]![branchRailAxis],
|
|
480
|
+
branchPath[railIndex + 1]![branchRailAxis],
|
|
463
481
|
].sort((a, b) => a - b)
|
|
464
482
|
const railsTouchAfterAlignment =
|
|
465
483
|
Math.min(donorRange[1]!, branchRange[1]!) >=
|
|
@@ -468,7 +486,7 @@ const getAlignedSharedEndpointRailPath = ({
|
|
|
468
486
|
|
|
469
487
|
const candidateFromShared = simplifyPath(
|
|
470
488
|
branchPath.map((point, index) =>
|
|
471
|
-
index ===
|
|
489
|
+
index === railIndex || index === railIndex + 1
|
|
472
490
|
? { ...point, [railCoordinateAxis]: donorCoordinate }
|
|
473
491
|
: point,
|
|
474
492
|
),
|