@tscircuit/schematic-trace-solver 0.0.148 → 0.0.150
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/.agents/skills/schematic-trace-visualization/SKILL.md +7 -2
- package/dist/index.d.ts +31 -2
- package/dist/index.js +127 -46
- package/lib/solvers/InlineNetLabelSolver/InlineNetLabelSolver.ts +115 -6
- package/lib/solvers/NetLabelPlacementSolver/NetLabelPlacementSolver.ts +17 -1
- package/lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/SingleNetLabelPlacementSolver.ts +2 -0
- package/lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/solvePortOnlyPin.ts +2 -0
- package/lib/types/InputProblem.ts +27 -1
- package/package.json +8 -1
- package/site/examples/example51.page.tsx +4 -0
- package/tests/assets/example51.json +5102 -0
- package/tests/bug-reports/bug-report-20260706T213649Z/__snapshots__/bug-report-20260706T213649Z.snap.svg +751 -5
- package/tests/bug-reports/bug-report-20260706T220324Z/__snapshots__/bug-report-20260706T220324Z.snap.svg +660 -5
- package/tests/bug-reports/bug-report-20260707T020342Z/__snapshots__/bug-report-20260707T020342Z.snap.svg +44 -5
- package/tests/bug-reports/bug-report-20260707T092615Z/__snapshots__/bug-report-20260707T092615Z.snap.svg +394 -5
- package/tests/bug-reports/bug-report-20260707T134549Z/__snapshots__/bug-report-20260707T134549Z.snap.svg +170 -5
- package/tests/bug-reports/bug-report-20260707T134722Z/__snapshots__/bug-report-20260707T134722Z.snap.svg +79 -5
- package/tests/bug-reports/bug-report-20260707T140410Z/__snapshots__/bug-report-20260707T140410Z.snap.svg +219 -5
- package/tests/bug-reports/bug-report-20260707T141025Z/__snapshots__/bug-report-20260707T141025Z.snap.svg +65 -5
- package/tests/bug-reports/bug-report-20260707T141421Z/__snapshots__/bug-report-20260707T141421Z.snap.svg +142 -5
- package/tests/bug-reports/bug-report-20260707T230831Z/__snapshots__/bug-report-20260707T230831Z.snap.svg +100 -5
- package/tests/bug-reports/bug-report-20260708T053736Z/__snapshots__/bug-report-20260708T053736Z.snap.svg +23 -5
- package/tests/bug-reports/bug-report-20260708T055430Z/__snapshots__/bug-report-20260708T055430Z.snap.svg +58 -5
- package/tests/bug-reports/bug-report-20260708T095725Z/__snapshots__/bug-report-20260708T095725Z.snap.svg +86 -5
- package/tests/bug-reports/bug-report-20260716T144856Z/__snapshots__/bug-report-20260716T144856Z.snap.svg +226 -5
- package/tests/bug-reports/bug-report-20260717T022934Z/__snapshots__/bug-report-20260717T022934Z.snap.svg +191 -5
- package/tests/bug-reports/bug-report-20260717T031704Z/__snapshots__/bug-report-20260717T031704Z.snap.svg +30 -5
- package/tests/bug-reports/bug-report-20260717T042845Z/__snapshots__/bug-report-20260717T042845Z.snap.svg +37 -5
- package/tests/bug-reports/bug-report-20260721T221026Z/__snapshots__/bug-report-20260721T221026Z.snap.svg +580 -2
- package/tests/bug-reports/bug-report-20260724T175257Z/__snapshots__/bug-report-20260724T175257Z.snap.svg +44 -5
- package/tests/bug-reports/bug-report-20260728T144234Z/__snapshots__/bug-report-20260728T144234Z.snap.svg +107 -5
- package/tests/bug-reports/bug-report-20260728T225606Z/__snapshots__/bug-report-20260728T225606Z.snap.svg +114 -5
- package/tests/bug-reports/bug-report-20260730T061837Z/__snapshots__/bug-report-20260730T061837Z.snap.svg +121 -5
- package/tests/bug-reports/bug-report-20260731T052229Z/__snapshots__/bug-report-20260731T052229Z.snap.svg +51 -5
- package/tests/bug-reports/bug-report-20260804T095800Z/__snapshots__/bug-report-20260804T095800Z.snap.svg +212 -5
- package/tests/bug-reports/bug-report-20260804T171919Z/__snapshots__/bug-report-20260804T171919Z.snap.svg +569 -5
- package/tests/bug-reports/bug-report-20260804T225912Z/__snapshots__/bug-report-20260804T225912Z.snap.svg +37 -5
- package/tests/bug-reports/bug-report-20260805T061316Z/__snapshots__/bug-report-20260805T061316Z.snap.svg +289 -5
- package/tests/bug-reports/bug-report-20260806T061548Z/__snapshots__/bug-report-20260806T061548Z.snap.svg +289 -5
- package/tests/bug-reports/bug-report-20260806T093501Z/__snapshots__/bug-report-20260806T093501Z.snap.svg +149 -5
- package/tests/bug-reports/bug-report-20260811T075142Z/__snapshots__/bug-report-20260811T075142Z.snap.svg +93 -5
- package/tests/bug-reports/bug-report-20260815T073240Z/__snapshots__/bug-report-20260815T073240Z.snap.svg +79 -5
- package/tests/bug-reports/bug-report-20260819T091818Z/__snapshots__/bug-report-20260819T091818Z.snap.svg +244 -2
- package/tests/examples/__snapshots__/example01.snap.svg +44 -5
- package/tests/examples/__snapshots__/example02.snap.svg +51 -5
- package/tests/examples/__snapshots__/example03.snap.svg +86 -5
- package/tests/examples/__snapshots__/example04.snap.svg +30 -5
- package/tests/examples/__snapshots__/example05.snap.svg +30 -5
- package/tests/examples/__snapshots__/example06.snap.svg +30 -5
- package/tests/examples/__snapshots__/example07.snap.svg +58 -5
- package/tests/examples/__snapshots__/example08.snap.svg +37 -5
- package/tests/examples/__snapshots__/example09.snap.svg +149 -5
- package/tests/examples/__snapshots__/example10.snap.svg +65 -5
- package/tests/examples/__snapshots__/example11.snap.svg +51 -5
- package/tests/examples/__snapshots__/example12.snap.svg +51 -5
- package/tests/examples/__snapshots__/example13.snap.svg +72 -5
- package/tests/examples/__snapshots__/example14.snap.svg +79 -5
- package/tests/examples/__snapshots__/example15.snap.svg +86 -5
- package/tests/examples/__snapshots__/example16.snap.svg +51 -5
- package/tests/examples/__snapshots__/example17.snap.svg +51 -5
- package/tests/examples/__snapshots__/example18.snap.svg +58 -5
- package/tests/examples/__snapshots__/example19.snap.svg +44 -5
- package/tests/examples/__snapshots__/example20.snap.svg +44 -5
- package/tests/examples/__snapshots__/example21.snap.svg +72 -5
- package/tests/examples/__snapshots__/example22.snap.svg +51 -5
- package/tests/examples/__snapshots__/example23.snap.svg +51 -5
- package/tests/examples/__snapshots__/example24.snap.svg +51 -5
- package/tests/examples/__snapshots__/example25.snap.svg +86 -5
- package/tests/examples/__snapshots__/example26.snap.svg +51 -5
- package/tests/examples/__snapshots__/example27.snap.svg +72 -5
- package/tests/examples/__snapshots__/example28.snap.svg +44 -5
- package/tests/examples/__snapshots__/example29.snap.svg +324 -5
- package/tests/examples/__snapshots__/example30.snap.svg +107 -5
- package/tests/examples/__snapshots__/example31.snap.svg +37 -5
- package/tests/examples/__snapshots__/example32.snap.svg +149 -5
- package/tests/examples/__snapshots__/example33.snap.svg +93 -5
- package/tests/examples/__snapshots__/example34.snap.svg +51 -5
- package/tests/examples/__snapshots__/example35.snap.svg +58 -5
- package/tests/examples/__snapshots__/example36.snap.svg +44 -5
- package/tests/examples/__snapshots__/example37.snap.svg +72 -5
- package/tests/examples/__snapshots__/example38.snap.svg +30 -5
- package/tests/examples/__snapshots__/example39.snap.svg +37 -5
- package/tests/examples/__snapshots__/example40.snap.svg +100 -5
- package/tests/examples/__snapshots__/example41.snap.svg +44 -5
- package/tests/examples/__snapshots__/example42.snap.svg +65 -5
- package/tests/examples/__snapshots__/example43.snap.svg +58 -5
- package/tests/examples/__snapshots__/example44.snap.svg +107 -5
- package/tests/examples/__snapshots__/example45.snap.svg +51 -5
- package/tests/examples/__snapshots__/example46.snap.svg +93 -5
- package/tests/examples/__snapshots__/example47.snap.svg +93 -5
- package/tests/examples/__snapshots__/example48.snap.svg +65 -5
- package/tests/examples/__snapshots__/example49.snap.svg +177 -5
- package/tests/examples/__snapshots__/example50.snap.svg +93 -5
- package/tests/examples/__snapshots__/example51.snap.svg +952 -0
- package/tests/examples/example51.test.ts +12 -0
- package/tests/fixtures/convertSolverOutputToCircuitJson.test.ts +219 -0
- package/tests/fixtures/convertSolverOutputToCircuitJson.ts +1058 -0
- package/tests/fixtures/matcher.ts +45 -8
- package/tests/repros/__snapshots__/board-1273-trace-overlap-cycle.snap.svg +762 -2
- package/tests/repros/__snapshots__/board-15984-same-net-junction.snap.svg +111 -2
- package/tests/repros/__snapshots__/board1096-usb-label-overlap-iteration.snap.svg +167 -2
- package/tests/repros/__snapshots__/bugreport-001-gnd-overlap.snap.svg +65 -5
- package/tests/repros/__snapshots__/manufacturePartNumber-text-box.snap.svg +30 -5
- package/tests/repros/__snapshots__/netlabel-connector-through-rail-label.snap.svg +79 -5
- package/tests/repros/__snapshots__/repro-atmega328p-fault-pullup.snap.svg +65 -5
- package/tests/repros/__snapshots__/repro-atmega328p-missing-gnd-netlabel.snap.svg +149 -5
- package/tests/repros/__snapshots__/repro-board-589-regulator-section.snap.svg +55 -2
- package/tests/repros/__snapshots__/repro-board-648-esp12f-section.snap.svg +160 -2
- package/tests/repros/__snapshots__/repro-bq24074-battery-charger.snap.svg +135 -5
- package/tests/repros/__snapshots__/repro-bq25895-cross-net-trace-overlap.snap.svg +69 -2
- package/tests/repros/__snapshots__/repro-cc2340r5.snap.svg +86 -5
- package/tests/repros/__snapshots__/repro-core-555-power-cross-net-overlap.snap.svg +44 -5
- package/tests/repros/__snapshots__/repro-core-subcircuit-missing-ground.snap.svg +44 -5
- package/tests/repros/__snapshots__/repro-core-tb67s579ftg-inline-label-routing.snap.svg +260 -0
- package/tests/repros/__snapshots__/repro-example35-minimize-trace-crossing.snap.svg +335 -2
- package/tests/repros/__snapshots__/repro-ground-label-on-lower-rail-end.snap.svg +48 -2
- package/tests/repros/__snapshots__/repro-ina237-current-monitor.snap.svg +149 -5
- package/tests/repros/__snapshots__/repro-missing-trace-netlabel.snap.svg +72 -5
- package/tests/repros/__snapshots__/repro-netlabel-collision-687.snap.svg +100 -5
- package/tests/repros/__snapshots__/repro-netlabel-overlap-trace.snap.svg +51 -5
- package/tests/repros/__snapshots__/repro-nrf52810-clock-routing.snap.svg +90 -2
- package/tests/repros/__snapshots__/repro-power-group-rail-labels.snap.svg +37 -5
- package/tests/repros/__snapshots__/repro-rectifier-trace-overlap.snap.svg +44 -5
- package/tests/repros/__snapshots__/repro-rp2040-gamepad-trace-alignment.snap.svg +237 -2
- package/tests/repros/__snapshots__/repro-rp2040-usb-cc2-ground-overlap.snap.svg +72 -5
- package/tests/repros/__snapshots__/repro-rp2040-v3v3-label-placement.snap.svg +51 -5
- package/tests/repros/__snapshots__/repro-rp2040-zero-crystal-fallback-netlabels.snap.svg +30 -5
- package/tests/repros/__snapshots__/repro-ti-power-output-section.snap.svg +79 -5
- package/tests/repros/__snapshots__/repro-tida010076-j4-ground-bus.snap.svg +27 -2
- package/tests/repros/__snapshots__/repro-tida010076-page02.snap.svg +1150 -5
- package/tests/repros/__snapshots__/repro-tps61222-trace-intersection.snap.svg +51 -5
- package/tests/repros/__snapshots__/repro-type-c-16pin-self-connection.snap.svg +30 -5
- package/tests/repros/__snapshots__/repro-type-c-16pin-to-resistor.snap.svg +30 -5
- package/tests/repros/__snapshots__/repro-type-c-vbus-led-ground-label.snap.svg +44 -5
- package/tests/repros/__snapshots__/repro-usb-power-vbus-label-detour.snap.svg +685 -2
- package/tests/repros/__snapshots__/repro-vcc-pin1-detour.snap.svg +27 -2
- package/tests/repros/__snapshots__/repro129-host-custom-symbol-passives.snap.svg +51 -5
- package/tests/repros/__snapshots__/repro130-bq27441-fuel-gauge-trace-through-c1.snap.svg +100 -5
- package/tests/repros/__snapshots__/repro161-power-section-autolayout.snap.svg +107 -5
- package/tests/repros/__snapshots__/repro47-endpoint-obstacle-detour.snap.svg +51 -5
- package/tests/repros/__snapshots__/repro48-555-timer-vcc-rail-label.snap.svg +104 -2
- package/tests/repros/__snapshots__/repro5-escape-padded-text-obstacles.snap.svg +30 -5
- package/tests/repros/__snapshots__/repro51-overlap-junction-crossing.snap.svg +65 -5
- package/tests/repros/__snapshots__/repro84-stacked-gnd-label-orientation.snap.svg +27 -2
- package/tests/repros/__snapshots__/small-variant-resistor-facing-direction.snap.svg +58 -5
- package/tests/repros/__snapshots__/trace-overlap-box-resistor.snap.svg +37 -5
- package/tests/repros/assets/repro-core-tb67s579ftg-inline-label-routing.input.json +900 -0
- package/tests/repros/repro-core-tb67s579ftg-inline-label-routing.test.ts +40 -0
- package/tests/solvers/InlineNetLabelSolver/__snapshots__/fallback-net-label-width.snap.svg +25 -7
- package/tests/solvers/InlineNetLabelSolver/__snapshots__/inline-net-label-anchored-label-clearance.snap.svg +34 -2
- package/tests/solvers/InlineNetLabelSolver/__snapshots__/inline-net-label-port-stub.snap.svg +23 -5
- package/tests/solvers/InlineNetLabelSolver/__snapshots__/inline-net-label-two-pin-net.snap.svg +23 -5
- package/tests/solvers/InlineNetLabelSolver/__snapshots__/inline-net-label01.snap.svg +23 -5
- package/tests/solvers/InlineNetLabelSolver/__snapshots__/inline-net-label02.snap.svg +23 -5
- package/tests/solvers/InlineNetLabelSolver/__snapshots__/terminal-stub-trace-clearance.snap.svg +71 -0
- package/tests/solvers/InlineNetLabelSolver/fallback-net-label-width.test.ts +10 -1
- package/tests/solvers/InlineNetLabelSolver/terminal-stub-trace-clearance.test.ts +102 -0
- package/tests/solvers/SchematicTraceSingleLineSolver2/__snapshots__/SchematicTraceSingleLineSolver2_01-example17-d1_1-u1_1.snap.svg +23 -5
- package/tests/solvers/SchematicTraceSingleLineSolver2/__snapshots__/SchematicTraceSingleLineSolver2_repro47-short-opposing-pins.snap.svg +20 -2
- package/tests/solvers/TraceCleanupSolver/__snapshots__/TraceCleanupSolver.snap.svg +44 -5
- package/tests/solvers/TraceLabelOverlapAvoidanceSolver/__snapshots__/TraceLabelOverlapAvoidanceSolver.snap.svg +79 -5
- package/tests/solvers/TraceLabelOverlapAvoidanceSolver/sub-solver/__snapshots__/MergedNetLabelObstacles.snap.svg +44 -5
- package/tests/solvers/TraceLabelOverlapAvoidanceSolver/sub-solver/__snapshots__/OverlapAvoidanceStepSolver.snap.svg +23 -5
- package/tests/solvers/TraceLabelOverlapAvoidanceSolver/sub-solver/__snapshots__/SingleOverlapSolver.snap.svg +30 -5
|
@@ -48,7 +48,8 @@ const png = await getPngBufferFromGraphicsObject(graphics, {
|
|
|
48
48
|
|
|
49
49
|
## Existing Repo Helpers
|
|
50
50
|
|
|
51
|
-
- `tests/fixtures/matcher.ts`: `expect(solver).toMatchSolverSnapshot(import.meta.path)` converts
|
|
51
|
+
- `tests/fixtures/matcher.ts`: `expect(solver).toMatchSolverSnapshot(import.meta.path)` converts the solver's semantic output to Circuit JSON and renders it with `circuit-to-svg`. These snapshots hide the input rats nest by default.
|
|
52
|
+
- `tests/fixtures/convertSolverOutputToCircuitJson.ts`: builds snapshot Circuit JSON with schematic components/symbols, ports, routed traces, net labels, text, and boxes.
|
|
52
53
|
- `tests/fixtures/getLastStepGraphicsObject.ts`: filters a `GraphicsObject` to its highest numbered `step`.
|
|
53
54
|
- `tests/fixtures/getLastStepSvg.ts`: converts only the last step to SVG.
|
|
54
55
|
- `lib/testing/PipelineStageDebugRunner.ts`: runs `SchematicTracePipelineSolver` and writes per-stage PNG/SVG/graphics JSON artifacts.
|
|
@@ -56,7 +57,8 @@ const png = await getPngBufferFromGraphicsObject(graphics, {
|
|
|
56
57
|
|
|
57
58
|
## Minimal SVG Tests
|
|
58
59
|
|
|
59
|
-
Prefer focused solver SVG snapshots over broad dumps
|
|
60
|
+
Prefer focused solver SVG snapshots over broad dumps. Solver snapshots use the
|
|
61
|
+
semantic Circuit JSON renderer by default:
|
|
60
62
|
|
|
61
63
|
```ts
|
|
62
64
|
const solver = new SchematicTracePipelineSolver(inputProblem as any)
|
|
@@ -64,6 +66,9 @@ solver.solve()
|
|
|
64
66
|
expect(solver).toMatchSolverSnapshot(import.meta.path)
|
|
65
67
|
```
|
|
66
68
|
|
|
69
|
+
Use `solver.visualize()` with `getSvgFromGraphicsObject` directly when a test is
|
|
70
|
+
specifically about internal candidates, failed geometry, or staged debug state.
|
|
71
|
+
|
|
67
72
|
For multi-step graphics where only the final stage matters:
|
|
68
73
|
|
|
69
74
|
```ts
|
package/dist/index.d.ts
CHANGED
|
@@ -75,6 +75,13 @@ interface TextBoxes {
|
|
|
75
75
|
}
|
|
76
76
|
interface InputChip {
|
|
77
77
|
chipId: ChipId;
|
|
78
|
+
/**
|
|
79
|
+
* Exact directional/oriented schematic-symbol name when the caller has it.
|
|
80
|
+
* `center`, `width`, and `height` describe the solver obstacle and may be
|
|
81
|
+
* expanded to include reference/value or manufacturer-part-number text, so
|
|
82
|
+
* renderers should use this symbol's geometry for the component body.
|
|
83
|
+
*/
|
|
84
|
+
symbolName?: string;
|
|
78
85
|
center: {
|
|
79
86
|
x: number;
|
|
80
87
|
y: number;
|
|
@@ -87,6 +94,13 @@ interface InputChip {
|
|
|
87
94
|
interface InputDirectConnection {
|
|
88
95
|
pinIds: [PinId, PinId];
|
|
89
96
|
netId?: string;
|
|
97
|
+
/**
|
|
98
|
+
* User-facing text to render for this net label. `netId` remains the stable
|
|
99
|
+
* connectivity identifier and may be an internal id. When this is omitted
|
|
100
|
+
* but a label width is provided, renderers should use a width-preserving
|
|
101
|
+
* placeholder instead of exposing `netId` as label text.
|
|
102
|
+
*/
|
|
103
|
+
netLabelText?: string;
|
|
90
104
|
netLabelWidth?: number;
|
|
91
105
|
/**
|
|
92
106
|
* Width of the conventional anchored label to use only when an inline label
|
|
@@ -109,7 +123,8 @@ interface InputDirectConnection {
|
|
|
109
123
|
allowInlineNetLabel?: boolean;
|
|
110
124
|
/**
|
|
111
125
|
* Extent of the inline net label along the trace. Falls back to
|
|
112
|
-
* `netLabelWidth`, then to an estimate from
|
|
126
|
+
* `netLabelWidth`, then to an estimate from `netLabelText` (or `netId` for
|
|
127
|
+
* backwards compatibility).
|
|
113
128
|
*/
|
|
114
129
|
inlineNetLabelWidth?: number;
|
|
115
130
|
/**
|
|
@@ -121,6 +136,13 @@ interface InputDirectConnection {
|
|
|
121
136
|
interface InputNetConnection {
|
|
122
137
|
netId: string;
|
|
123
138
|
pinIds: Array<PinId>;
|
|
139
|
+
/**
|
|
140
|
+
* User-facing text to render for this net label. `netId` remains the stable
|
|
141
|
+
* connectivity identifier and may be an internal id. When this is omitted
|
|
142
|
+
* but a label width is provided, renderers should use a width-preserving
|
|
143
|
+
* placeholder instead of exposing `netId` as label text.
|
|
144
|
+
*/
|
|
145
|
+
netLabelText?: string;
|
|
124
146
|
netLabelWidth?: number;
|
|
125
147
|
fallbackNetLabelWidth?: number;
|
|
126
148
|
netLabelHeight?: number;
|
|
@@ -425,6 +447,7 @@ declare class SingleNetLabelPlacementSolver extends BaseSolver {
|
|
|
425
447
|
type OverlappingSameNetTraceGroup = {
|
|
426
448
|
globalConnNetId: string;
|
|
427
449
|
netId?: string;
|
|
450
|
+
netLabelText?: string;
|
|
428
451
|
overlappingTraces?: SolvedTracePath;
|
|
429
452
|
portOnlyPinId?: string;
|
|
430
453
|
mspConnectionPairIds?: MspConnectionPairId[];
|
|
@@ -436,6 +459,8 @@ interface NetLabelPlacement {
|
|
|
436
459
|
* Optional user-provided net identifier (if present in the input problem).
|
|
437
460
|
*/
|
|
438
461
|
netId?: string;
|
|
462
|
+
/** User-facing label content, separate from the connectivity identifier. */
|
|
463
|
+
netLabelText?: string;
|
|
439
464
|
/**
|
|
440
465
|
* MSP pair ids that the label is associated with. Port-only labels use [].
|
|
441
466
|
*/
|
|
@@ -1186,6 +1211,8 @@ declare const DEFAULT_INLINE_NET_LABEL_HEIGHT = 0.18;
|
|
|
1186
1211
|
* Gap between the trace and the near edge of the inline label text.
|
|
1187
1212
|
*/
|
|
1188
1213
|
declare const INLINE_NET_LABEL_TRACE_MARGIN = 0.05;
|
|
1214
|
+
/** Clearance between a generated terminal stub and an unrelated trace. */
|
|
1215
|
+
declare const INLINE_NET_LABEL_STUB_TRACE_CLEARANCE = 0.05;
|
|
1189
1216
|
/**
|
|
1190
1217
|
* Largest perpendicular deviation a route may have and still be labeled as one
|
|
1191
1218
|
* span. A route that is straight except for elbow jogs up to this size reads
|
|
@@ -1207,6 +1234,8 @@ declare const INLINE_NET_LABEL_MAX_SPAN_JOG = 0.4;
|
|
|
1207
1234
|
interface InlineNetLabelPlacement {
|
|
1208
1235
|
globalConnNetId: string;
|
|
1209
1236
|
netId?: string;
|
|
1237
|
+
/** User-facing label content, separate from the connectivity identifier. */
|
|
1238
|
+
netLabelText?: string;
|
|
1210
1239
|
mspPairId?: string;
|
|
1211
1240
|
pinIds: PinId[];
|
|
1212
1241
|
/**
|
|
@@ -1361,4 +1390,4 @@ declare class SchematicTracePipelineSolver extends BaseSolver {
|
|
|
1361
1390
|
preview(): GraphicsObject;
|
|
1362
1391
|
}
|
|
1363
1392
|
|
|
1364
|
-
export { type ChipId, DEFAULT_INLINE_NET_LABEL_HEIGHT, INLINE_NET_LABEL_MAX_SPAN_JOG, INLINE_NET_LABEL_TRACE_MARGIN, type InlineNetLabelPlacement, InlineNetLabelSolver, type InputChip, type InputDirectConnection, type InputNetConnection, type InputPin, type InputProblem, type NetId, type NetLabelPlacement, type PinId, SchematicTracePipelineSolver, SchematicTraceSingleLineSolver2, type SectionId, type TextBoxes, estimateInlineNetLabelWidth };
|
|
1393
|
+
export { type ChipId, DEFAULT_INLINE_NET_LABEL_HEIGHT, INLINE_NET_LABEL_MAX_SPAN_JOG, INLINE_NET_LABEL_STUB_TRACE_CLEARANCE, INLINE_NET_LABEL_TRACE_MARGIN, type InlineNetLabelPlacement, InlineNetLabelSolver, type InputChip, type InputDirectConnection, type InputNetConnection, type InputPin, type InputProblem, type NetId, type NetLabelPlacement, type PinId, SchematicTracePipelineSolver, SchematicTraceSingleLineSolver2, type SectionId, type TextBoxes, estimateInlineNetLabelWidth };
|
package/dist/index.js
CHANGED
|
@@ -2742,6 +2742,7 @@ function solveNetLabelPlacementForPortOnlyPin(params) {
|
|
|
2742
2742
|
globalConnNetId: overlappingSameNetTraceGroup.globalConnNetId,
|
|
2743
2743
|
dcConnNetId: void 0,
|
|
2744
2744
|
netId: overlappingSameNetTraceGroup.netId,
|
|
2745
|
+
netLabelText: overlappingSameNetTraceGroup.netLabelText,
|
|
2745
2746
|
mspConnectionPairIds: [],
|
|
2746
2747
|
pinIds: [pinId],
|
|
2747
2748
|
orientation,
|
|
@@ -2773,6 +2774,7 @@ function solveNetLabelPlacementForPortOnlyPin(params) {
|
|
|
2773
2774
|
globalConnNetId: overlappingSameNetTraceGroup.globalConnNetId,
|
|
2774
2775
|
dcConnNetId: void 0,
|
|
2775
2776
|
netId: overlappingSameNetTraceGroup.netId,
|
|
2777
|
+
netLabelText: overlappingSameNetTraceGroup.netLabelText,
|
|
2776
2778
|
mspConnectionPairIds: [],
|
|
2777
2779
|
pinIds: [pinId],
|
|
2778
2780
|
orientation: fallbackOrientation,
|
|
@@ -3059,6 +3061,7 @@ var SingleNetLabelPlacementSolver = class extends BaseSolver {
|
|
|
3059
3061
|
globalConnNetId: this.overlappingSameNetTraceGroup.globalConnNetId,
|
|
3060
3062
|
dcConnNetId: curr.dcConnNetId,
|
|
3061
3063
|
netId: this.overlappingSameNetTraceGroup.netId,
|
|
3064
|
+
netLabelText: this.overlappingSameNetTraceGroup.netLabelText,
|
|
3062
3065
|
mspConnectionPairIds: [curr.mspPairId],
|
|
3063
3066
|
pinIds: [curr.pins[0].pinId, curr.pins[1].pinId],
|
|
3064
3067
|
orientation,
|
|
@@ -3078,6 +3081,7 @@ var SingleNetLabelPlacementSolver = class extends BaseSolver {
|
|
|
3078
3081
|
globalConnNetId: this.overlappingSameNetTraceGroup.globalConnNetId,
|
|
3079
3082
|
dcConnNetId: bestCandidate.dcConnNetId,
|
|
3080
3083
|
netId: this.overlappingSameNetTraceGroup.netId,
|
|
3084
|
+
netLabelText: this.overlappingSameNetTraceGroup.netLabelText,
|
|
3081
3085
|
mspConnectionPairIds: [bestCandidate.mspPairId],
|
|
3082
3086
|
pinIds: bestCandidate.pinIds,
|
|
3083
3087
|
orientation: bestCandidate.orientation,
|
|
@@ -3133,16 +3137,25 @@ var NetLabelPlacementSolver = class extends BaseSolver {
|
|
|
3133
3137
|
}
|
|
3134
3138
|
}
|
|
3135
3139
|
const userNetIdByPinId = {};
|
|
3140
|
+
const netLabelTextByPinId = {};
|
|
3136
3141
|
for (const dc of this.inputProblem.directConnections) {
|
|
3137
3142
|
if (dc.netId) {
|
|
3138
3143
|
const [a, b] = dc.pinIds;
|
|
3139
3144
|
userNetIdByPinId[a] = dc.netId;
|
|
3140
3145
|
userNetIdByPinId[b] = dc.netId;
|
|
3141
3146
|
}
|
|
3147
|
+
const netLabelText = dc.netLabelText?.trim();
|
|
3148
|
+
if (netLabelText) {
|
|
3149
|
+
const [a, b] = dc.pinIds;
|
|
3150
|
+
netLabelTextByPinId[a] = netLabelText;
|
|
3151
|
+
netLabelTextByPinId[b] = netLabelText;
|
|
3152
|
+
}
|
|
3142
3153
|
}
|
|
3143
3154
|
for (const nc of this.inputProblem.netConnections) {
|
|
3144
3155
|
for (const pid of nc.pinIds) {
|
|
3145
3156
|
userNetIdByPinId[pid] = nc.netId;
|
|
3157
|
+
const netLabelText = nc.netLabelText?.trim();
|
|
3158
|
+
if (netLabelText) netLabelTextByPinId[pid] = netLabelText;
|
|
3146
3159
|
}
|
|
3147
3160
|
}
|
|
3148
3161
|
const groups = [];
|
|
@@ -3228,6 +3241,7 @@ var NetLabelPlacementSolver = class extends BaseSolver {
|
|
|
3228
3241
|
const group = {
|
|
3229
3242
|
globalConnNetId,
|
|
3230
3243
|
netId: userNetId,
|
|
3244
|
+
netLabelText: [...component].map((pinId) => netLabelTextByPinId[pinId]).find((text) => Boolean(text)),
|
|
3231
3245
|
overlappingTraces: rep,
|
|
3232
3246
|
mspConnectionPairIds
|
|
3233
3247
|
};
|
|
@@ -3239,6 +3253,7 @@ var NetLabelPlacementSolver = class extends BaseSolver {
|
|
|
3239
3253
|
groups.push({
|
|
3240
3254
|
globalConnNetId,
|
|
3241
3255
|
netId: userNetId,
|
|
3256
|
+
netLabelText: netLabelTextByPinId[p],
|
|
3242
3257
|
portOnlyPinId: p
|
|
3243
3258
|
});
|
|
3244
3259
|
}
|
|
@@ -12678,47 +12693,6 @@ var TraceElbowTransitionSimplificationSolver = class extends BaseSolver {
|
|
|
12678
12693
|
}
|
|
12679
12694
|
};
|
|
12680
12695
|
|
|
12681
|
-
// lib/solvers/InlineNetLabelSolver/getAxisAlignedSegments.ts
|
|
12682
|
-
var getAxisAlignedSegments = (path, epsilon = 1e-6) => {
|
|
12683
|
-
const segments = [];
|
|
12684
|
-
let runStart = null;
|
|
12685
|
-
let runAxis = null;
|
|
12686
|
-
let runSign = 0;
|
|
12687
|
-
const closeRun = (runEnd) => {
|
|
12688
|
-
if (runStart && runAxis) {
|
|
12689
|
-
const length = runAxis === "x" ? Math.abs(runEnd.x - runStart.x) : Math.abs(runEnd.y - runStart.y);
|
|
12690
|
-
if (length > epsilon) {
|
|
12691
|
-
segments.push({ start: runStart, end: runEnd, axis: runAxis, length });
|
|
12692
|
-
}
|
|
12693
|
-
}
|
|
12694
|
-
runStart = null;
|
|
12695
|
-
runAxis = null;
|
|
12696
|
-
runSign = 0;
|
|
12697
|
-
};
|
|
12698
|
-
for (let i = 0; i < path.length - 1; i++) {
|
|
12699
|
-
const a = path[i];
|
|
12700
|
-
const b = path[i + 1];
|
|
12701
|
-
const dx = b.x - a.x;
|
|
12702
|
-
const dy = b.y - a.y;
|
|
12703
|
-
if (Math.abs(dx) <= epsilon && Math.abs(dy) <= epsilon) continue;
|
|
12704
|
-
const axis = Math.abs(dy) <= epsilon ? "x" : Math.abs(dx) <= epsilon ? "y" : null;
|
|
12705
|
-
if (!axis) {
|
|
12706
|
-
closeRun(a);
|
|
12707
|
-
continue;
|
|
12708
|
-
}
|
|
12709
|
-
const sign = Math.sign(axis === "x" ? dx : dy);
|
|
12710
|
-
if (runStart && runAxis === axis && runSign === sign) continue;
|
|
12711
|
-
closeRun(a);
|
|
12712
|
-
runStart = a;
|
|
12713
|
-
runAxis = axis;
|
|
12714
|
-
runSign = sign;
|
|
12715
|
-
}
|
|
12716
|
-
if (path.length >= 2) {
|
|
12717
|
-
closeRun(path[path.length - 1]);
|
|
12718
|
-
}
|
|
12719
|
-
return segments.sort((a, b) => b.length - a.length);
|
|
12720
|
-
};
|
|
12721
|
-
|
|
12722
12696
|
// lib/solvers/InlineNetLabelSolver/alignPortOnlyInlineNetLabelStubs.ts
|
|
12723
12697
|
var getStubDirection = (path) => {
|
|
12724
12698
|
const [start, end] = path;
|
|
@@ -12867,6 +12841,47 @@ var alignPortOnlyInlineNetLabelStubs = ({
|
|
|
12867
12841
|
return alignedPlacements;
|
|
12868
12842
|
};
|
|
12869
12843
|
|
|
12844
|
+
// lib/solvers/InlineNetLabelSolver/getAxisAlignedSegments.ts
|
|
12845
|
+
var getAxisAlignedSegments = (path, epsilon = 1e-6) => {
|
|
12846
|
+
const segments = [];
|
|
12847
|
+
let runStart = null;
|
|
12848
|
+
let runAxis = null;
|
|
12849
|
+
let runSign = 0;
|
|
12850
|
+
const closeRun = (runEnd) => {
|
|
12851
|
+
if (runStart && runAxis) {
|
|
12852
|
+
const length = runAxis === "x" ? Math.abs(runEnd.x - runStart.x) : Math.abs(runEnd.y - runStart.y);
|
|
12853
|
+
if (length > epsilon) {
|
|
12854
|
+
segments.push({ start: runStart, end: runEnd, axis: runAxis, length });
|
|
12855
|
+
}
|
|
12856
|
+
}
|
|
12857
|
+
runStart = null;
|
|
12858
|
+
runAxis = null;
|
|
12859
|
+
runSign = 0;
|
|
12860
|
+
};
|
|
12861
|
+
for (let i = 0; i < path.length - 1; i++) {
|
|
12862
|
+
const a = path[i];
|
|
12863
|
+
const b = path[i + 1];
|
|
12864
|
+
const dx = b.x - a.x;
|
|
12865
|
+
const dy = b.y - a.y;
|
|
12866
|
+
if (Math.abs(dx) <= epsilon && Math.abs(dy) <= epsilon) continue;
|
|
12867
|
+
const axis = Math.abs(dy) <= epsilon ? "x" : Math.abs(dx) <= epsilon ? "y" : null;
|
|
12868
|
+
if (!axis) {
|
|
12869
|
+
closeRun(a);
|
|
12870
|
+
continue;
|
|
12871
|
+
}
|
|
12872
|
+
const sign = Math.sign(axis === "x" ? dx : dy);
|
|
12873
|
+
if (runStart && runAxis === axis && runSign === sign) continue;
|
|
12874
|
+
closeRun(a);
|
|
12875
|
+
runStart = a;
|
|
12876
|
+
runAxis = axis;
|
|
12877
|
+
runSign = sign;
|
|
12878
|
+
}
|
|
12879
|
+
if (path.length >= 2) {
|
|
12880
|
+
closeRun(path[path.length - 1]);
|
|
12881
|
+
}
|
|
12882
|
+
return segments.sort((a, b) => b.length - a.length);
|
|
12883
|
+
};
|
|
12884
|
+
|
|
12870
12885
|
// lib/solvers/InlineNetLabelSolver/pushAnchoredNetLabelsAwayFromInlineLabels.ts
|
|
12871
12886
|
var LABEL_CLEARANCE2 = 0.05;
|
|
12872
12887
|
var POINT_EPSILON = 1e-6;
|
|
@@ -13229,6 +13244,7 @@ var pushAnchoredNetLabelsAwayFromInlineLabels = ({
|
|
|
13229
13244
|
// lib/solvers/InlineNetLabelSolver/InlineNetLabelSolver.ts
|
|
13230
13245
|
var DEFAULT_INLINE_NET_LABEL_HEIGHT = 0.18;
|
|
13231
13246
|
var INLINE_NET_LABEL_TRACE_MARGIN = 0.05;
|
|
13247
|
+
var INLINE_NET_LABEL_STUB_TRACE_CLEARANCE = 0.05;
|
|
13232
13248
|
var INLINE_NET_LABEL_MAX_SPAN_JOG = 0.4;
|
|
13233
13249
|
var getPinPairKey2 = (pinIds) => [...pinIds].sort().join("::");
|
|
13234
13250
|
var InlineNetLabelSolver = class extends BaseSolver {
|
|
@@ -13325,11 +13341,20 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
13325
13341
|
);
|
|
13326
13342
|
const inputPin = inputChip?.pins.find((pin) => pin.pinId === pinId);
|
|
13327
13343
|
const height = connection.inlineNetLabelHeight ?? DEFAULT_INLINE_NET_LABEL_HEIGHT;
|
|
13328
|
-
const
|
|
13344
|
+
const netLabelText = connection.netLabelText?.trim() || void 0;
|
|
13345
|
+
const width = connection.inlineNetLabelWidth ?? connection.netLabelWidth ?? estimateInlineNetLabelWidth(netLabelText ?? connection.netId, height);
|
|
13329
13346
|
const stubLength = Math.max(width + 0.2, 0.6);
|
|
13330
13347
|
const start = inputPin ? { x: inputPin.x, y: inputPin.y } : anchoredPlacement.anchorPoint;
|
|
13331
13348
|
const direction = inputPin && inputChip ? inputPin._facingDirection ?? getPinDirection(inputPin, inputChip) : anchoredPlacement.orientation;
|
|
13332
|
-
const
|
|
13349
|
+
const intendedEnd = direction === "x+" ? { x: start.x + stubLength, y: start.y } : direction === "x-" ? { x: start.x - stubLength, y: start.y } : direction === "y+" ? { x: start.x, y: start.y + stubLength } : { x: start.x, y: start.y - stubLength };
|
|
13350
|
+
const end = getCollisionLimitedTerminalStubEnd({
|
|
13351
|
+
start,
|
|
13352
|
+
intendedEnd,
|
|
13353
|
+
minimumLength: width + 2 * INLINE_NET_LABEL_TRACE_MARGIN,
|
|
13354
|
+
traces: this.traces,
|
|
13355
|
+
ownGlobalConnNetId: anchoredPlacement.globalConnNetId
|
|
13356
|
+
});
|
|
13357
|
+
if (!end) return null;
|
|
13333
13358
|
const axis = direction === "x+" || direction === "x-" ? "x" : "y";
|
|
13334
13359
|
const side = axis === "x" ? "y+" : "x-";
|
|
13335
13360
|
const anchorPoint = {
|
|
@@ -13359,6 +13384,7 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
13359
13384
|
return {
|
|
13360
13385
|
globalConnNetId: anchoredPlacement.globalConnNetId,
|
|
13361
13386
|
netId: connection.netId,
|
|
13387
|
+
netLabelText,
|
|
13362
13388
|
pinIds: [pinId],
|
|
13363
13389
|
stubTracePath: [start, end],
|
|
13364
13390
|
axis,
|
|
@@ -13376,7 +13402,8 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
13376
13402
|
const segments = getAxisAlignedSegments(trace.tracePath);
|
|
13377
13403
|
if (segments.length === 0) return null;
|
|
13378
13404
|
const height = connection.inlineNetLabelHeight ?? DEFAULT_INLINE_NET_LABEL_HEIGHT;
|
|
13379
|
-
const
|
|
13405
|
+
const netLabelText = connection.netLabelText?.trim() || void 0;
|
|
13406
|
+
const width = connection.inlineNetLabelWidth ?? connection.netLabelWidth ?? estimateInlineNetLabelWidth(netLabelText ?? connection.netId, height);
|
|
13380
13407
|
const offset = height / 2 + INLINE_NET_LABEL_TRACE_MARGIN;
|
|
13381
13408
|
const usableSegments = segments.filter((segment) => segment.length >= width).sort((a, b) => b.length - a.length);
|
|
13382
13409
|
for (const segment of usableSegments) {
|
|
@@ -13405,6 +13432,7 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
13405
13432
|
return {
|
|
13406
13433
|
globalConnNetId: trace.globalConnNetId,
|
|
13407
13434
|
netId: connection.netId,
|
|
13435
|
+
netLabelText,
|
|
13408
13436
|
mspPairId: trace.mspPairId,
|
|
13409
13437
|
pinIds: [...connection.pinIds],
|
|
13410
13438
|
axis: segment.axis,
|
|
@@ -13420,6 +13448,7 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
13420
13448
|
const spanPlacement = this.computeSpanPlacement({
|
|
13421
13449
|
trace,
|
|
13422
13450
|
connection,
|
|
13451
|
+
netLabelText,
|
|
13423
13452
|
width,
|
|
13424
13453
|
height,
|
|
13425
13454
|
offset
|
|
@@ -13436,6 +13465,7 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
13436
13465
|
computeSpanPlacement({
|
|
13437
13466
|
trace,
|
|
13438
13467
|
connection,
|
|
13468
|
+
netLabelText,
|
|
13439
13469
|
width,
|
|
13440
13470
|
height,
|
|
13441
13471
|
offset
|
|
@@ -13495,6 +13525,7 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
13495
13525
|
return {
|
|
13496
13526
|
globalConnNetId: trace.globalConnNetId,
|
|
13497
13527
|
netId: connection.netId,
|
|
13528
|
+
netLabelText,
|
|
13498
13529
|
mspPairId: trace.mspPairId,
|
|
13499
13530
|
pinIds: [...connection.pinIds],
|
|
13500
13531
|
axis,
|
|
@@ -13629,7 +13660,7 @@ orientation: ${label.orientation}`
|
|
|
13629
13660
|
graphics.texts.push({
|
|
13630
13661
|
x: inlineLabel.stubTracePath && inlineLabel.axis === "x" ? inlineLabel.center.x + (inlineLabel.stubTracePath[1].x > inlineLabel.stubTracePath[0].x ? -inlineLabel.width / 2 : inlineLabel.width / 2) : inlineLabel.center.x,
|
|
13631
13662
|
y: inlineLabel.stubTracePath && inlineLabel.axis === "y" ? inlineLabel.center.y + (inlineLabel.stubTracePath[1].y > inlineLabel.stubTracePath[0].y ? -inlineLabel.width / 2 : inlineLabel.width / 2) : inlineLabel.center.y,
|
|
13632
|
-
text: inlineLabel.netId ?? "",
|
|
13663
|
+
text: inlineLabel.netLabelText ?? inlineLabel.netId ?? "",
|
|
13633
13664
|
color: "green",
|
|
13634
13665
|
fontSize: inlineLabel.height,
|
|
13635
13666
|
anchorSide: inlineLabel.stubTracePath ? inlineLabel.stubTracePath[1][inlineLabel.axis] > inlineLabel.stubTracePath[0][inlineLabel.axis] ? "center_left" : "center_right" : "center",
|
|
@@ -13641,7 +13672,7 @@ orientation: ${label.orientation}`
|
|
|
13641
13672
|
y: inlineLabel.anchorPoint.y,
|
|
13642
13673
|
color: "green",
|
|
13643
13674
|
label: `inline anchor
|
|
13644
|
-
${inlineLabel.netId}`
|
|
13675
|
+
${inlineLabel.netLabelText ?? inlineLabel.netId}`
|
|
13645
13676
|
});
|
|
13646
13677
|
}
|
|
13647
13678
|
return graphics;
|
|
@@ -13681,6 +13712,55 @@ var doesPathIntersectBounds2 = (path, bounds) => {
|
|
|
13681
13712
|
}
|
|
13682
13713
|
return false;
|
|
13683
13714
|
};
|
|
13715
|
+
var GEOMETRY_EPSILON = 1e-6;
|
|
13716
|
+
var getCollisionLimitedTerminalStubEnd = ({
|
|
13717
|
+
start,
|
|
13718
|
+
intendedEnd,
|
|
13719
|
+
minimumLength,
|
|
13720
|
+
traces,
|
|
13721
|
+
ownGlobalConnNetId
|
|
13722
|
+
}) => {
|
|
13723
|
+
const isHorizontal4 = Math.abs(intendedEnd.x - start.x) >= Math.abs(intendedEnd.y - start.y);
|
|
13724
|
+
const alongAxis = isHorizontal4 ? "x" : "y";
|
|
13725
|
+
const acrossAxis = isHorizontal4 ? "y" : "x";
|
|
13726
|
+
const direction = Math.sign(intendedEnd[alongAxis] - start[alongAxis]) || 1;
|
|
13727
|
+
const intendedLength = Math.abs(intendedEnd[alongAxis] - start[alongAxis]);
|
|
13728
|
+
let availableLength = intendedLength;
|
|
13729
|
+
for (const trace of traces) {
|
|
13730
|
+
if (trace.globalConnNetId === ownGlobalConnNetId) continue;
|
|
13731
|
+
for (let segmentIndex = 0; segmentIndex < trace.tracePath.length - 1; segmentIndex++) {
|
|
13732
|
+
const segmentStart = trace.tracePath[segmentIndex];
|
|
13733
|
+
const segmentEnd = trace.tracePath[segmentIndex + 1];
|
|
13734
|
+
const startAlong = (segmentStart[alongAxis] - start[alongAxis]) * direction;
|
|
13735
|
+
const endAlong = (segmentEnd[alongAxis] - start[alongAxis]) * direction;
|
|
13736
|
+
const startAcross = segmentStart[acrossAxis] - start[acrossAxis];
|
|
13737
|
+
const endAcross = segmentEnd[acrossAxis] - start[acrossAxis];
|
|
13738
|
+
const minAlong = Math.min(startAlong, endAlong);
|
|
13739
|
+
const maxAlong = Math.max(startAlong, endAlong);
|
|
13740
|
+
const minAcross = Math.min(startAcross, endAcross);
|
|
13741
|
+
const maxAcross = Math.max(startAcross, endAcross);
|
|
13742
|
+
let collisionDistance;
|
|
13743
|
+
const isCollinear = Math.abs(startAcross) <= GEOMETRY_EPSILON && Math.abs(endAcross) <= GEOMETRY_EPSILON;
|
|
13744
|
+
if (isCollinear && maxAlong >= -GEOMETRY_EPSILON && minAlong <= intendedLength + GEOMETRY_EPSILON) {
|
|
13745
|
+
collisionDistance = Math.max(0, minAlong);
|
|
13746
|
+
} else {
|
|
13747
|
+
const crossesStubAxis = minAcross <= GEOMETRY_EPSILON && maxAcross >= -GEOMETRY_EPSILON;
|
|
13748
|
+
const perpendicularAlong = (startAlong + endAlong) / 2;
|
|
13749
|
+
if (crossesStubAxis && Math.abs(startAlong - endAlong) <= GEOMETRY_EPSILON && perpendicularAlong >= -GEOMETRY_EPSILON && perpendicularAlong <= intendedLength + GEOMETRY_EPSILON) {
|
|
13750
|
+
collisionDistance = Math.max(0, perpendicularAlong);
|
|
13751
|
+
}
|
|
13752
|
+
}
|
|
13753
|
+
if (collisionDistance !== void 0) {
|
|
13754
|
+
availableLength = Math.min(
|
|
13755
|
+
availableLength,
|
|
13756
|
+
collisionDistance - INLINE_NET_LABEL_STUB_TRACE_CLEARANCE
|
|
13757
|
+
);
|
|
13758
|
+
}
|
|
13759
|
+
}
|
|
13760
|
+
}
|
|
13761
|
+
if (availableLength + GEOMETRY_EPSILON < minimumLength) return null;
|
|
13762
|
+
return isHorizontal4 ? { x: start.x + direction * availableLength, y: start.y } : { x: start.x, y: start.y + direction * availableLength };
|
|
13763
|
+
};
|
|
13684
13764
|
|
|
13685
13765
|
// lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver.ts
|
|
13686
13766
|
function definePipelineStep(solverName, solverClass, getConstructorParams, opts = {}) {
|
|
@@ -14246,6 +14326,7 @@ var SchematicTracePipelineSolver = class extends BaseSolver {
|
|
|
14246
14326
|
export {
|
|
14247
14327
|
DEFAULT_INLINE_NET_LABEL_HEIGHT,
|
|
14248
14328
|
INLINE_NET_LABEL_MAX_SPAN_JOG,
|
|
14329
|
+
INLINE_NET_LABEL_STUB_TRACE_CLEARANCE,
|
|
14249
14330
|
INLINE_NET_LABEL_TRACE_MARGIN,
|
|
14250
14331
|
InlineNetLabelSolver,
|
|
14251
14332
|
SchematicTracePipelineSolver,
|
|
@@ -13,11 +13,11 @@ import type {
|
|
|
13
13
|
} from "lib/types/InputProblem"
|
|
14
14
|
import { getColorFromString } from "lib/utils/getColorFromString"
|
|
15
15
|
import { boundsOverlap, getTextBoxBounds } from "lib/utils/textBoxBounds"
|
|
16
|
+
import { alignPortOnlyInlineNetLabelStubs } from "./alignPortOnlyInlineNetLabelStubs"
|
|
16
17
|
import {
|
|
17
18
|
type AxisAlignedSegment,
|
|
18
19
|
getAxisAlignedSegments,
|
|
19
20
|
} from "./getAxisAlignedSegments"
|
|
20
|
-
import { alignPortOnlyInlineNetLabelStubs } from "./alignPortOnlyInlineNetLabelStubs"
|
|
21
21
|
import { pushAnchoredNetLabelsAwayFromInlineLabels } from "./pushAnchoredNetLabelsAwayFromInlineLabels"
|
|
22
22
|
|
|
23
23
|
export const DEFAULT_INLINE_NET_LABEL_HEIGHT = 0.18
|
|
@@ -27,6 +27,9 @@ export const DEFAULT_INLINE_NET_LABEL_HEIGHT = 0.18
|
|
|
27
27
|
*/
|
|
28
28
|
export const INLINE_NET_LABEL_TRACE_MARGIN = 0.05
|
|
29
29
|
|
|
30
|
+
/** Clearance between a generated terminal stub and an unrelated trace. */
|
|
31
|
+
export const INLINE_NET_LABEL_STUB_TRACE_CLEARANCE = 0.05
|
|
32
|
+
|
|
30
33
|
/**
|
|
31
34
|
* Largest perpendicular deviation a route may have and still be labeled as one
|
|
32
35
|
* span. A route that is straight except for elbow jogs up to this size reads
|
|
@@ -49,6 +52,8 @@ export const INLINE_NET_LABEL_MAX_SPAN_JOG = 0.4
|
|
|
49
52
|
export interface InlineNetLabelPlacement {
|
|
50
53
|
globalConnNetId: string
|
|
51
54
|
netId?: string
|
|
55
|
+
/** User-facing label content, separate from the connectivity identifier. */
|
|
56
|
+
netLabelText?: string
|
|
52
57
|
mspPairId?: string
|
|
53
58
|
pinIds: PinId[]
|
|
54
59
|
|
|
@@ -233,10 +238,11 @@ export class InlineNetLabelSolver extends BaseSolver {
|
|
|
233
238
|
|
|
234
239
|
const height =
|
|
235
240
|
connection.inlineNetLabelHeight ?? DEFAULT_INLINE_NET_LABEL_HEIGHT
|
|
241
|
+
const netLabelText = connection.netLabelText?.trim() || undefined
|
|
236
242
|
const width =
|
|
237
243
|
connection.inlineNetLabelWidth ??
|
|
238
244
|
connection.netLabelWidth ??
|
|
239
|
-
estimateInlineNetLabelWidth(connection.netId, height)
|
|
245
|
+
estimateInlineNetLabelWidth(netLabelText ?? connection.netId, height)
|
|
240
246
|
|
|
241
247
|
// Leave a small wire tail at both ends of the text so it unmistakably
|
|
242
248
|
// reads as a label on a trace rather than free-standing text.
|
|
@@ -248,7 +254,7 @@ export class InlineNetLabelSolver extends BaseSolver {
|
|
|
248
254
|
inputPin && inputChip
|
|
249
255
|
? (inputPin._facingDirection ?? getPinDirection(inputPin, inputChip))
|
|
250
256
|
: anchoredPlacement.orientation
|
|
251
|
-
const
|
|
257
|
+
const intendedEnd: Point =
|
|
252
258
|
direction === "x+"
|
|
253
259
|
? { x: start.x + stubLength, y: start.y }
|
|
254
260
|
: direction === "x-"
|
|
@@ -257,6 +263,15 @@ export class InlineNetLabelSolver extends BaseSolver {
|
|
|
257
263
|
? { x: start.x, y: start.y + stubLength }
|
|
258
264
|
: { x: start.x, y: start.y - stubLength }
|
|
259
265
|
|
|
266
|
+
const end = getCollisionLimitedTerminalStubEnd({
|
|
267
|
+
start,
|
|
268
|
+
intendedEnd,
|
|
269
|
+
minimumLength: width + 2 * INLINE_NET_LABEL_TRACE_MARGIN,
|
|
270
|
+
traces: this.traces,
|
|
271
|
+
ownGlobalConnNetId: anchoredPlacement.globalConnNetId,
|
|
272
|
+
})
|
|
273
|
+
if (!end) return null
|
|
274
|
+
|
|
260
275
|
const axis: InlineNetLabelPlacement["axis"] =
|
|
261
276
|
direction === "x+" || direction === "x-" ? "x" : "y"
|
|
262
277
|
const side: InlineNetLabelPlacement["side"] = axis === "x" ? "y+" : "x-"
|
|
@@ -298,6 +313,7 @@ export class InlineNetLabelSolver extends BaseSolver {
|
|
|
298
313
|
return {
|
|
299
314
|
globalConnNetId: anchoredPlacement.globalConnNetId,
|
|
300
315
|
netId: connection.netId,
|
|
316
|
+
netLabelText,
|
|
301
317
|
pinIds: [pinId],
|
|
302
318
|
stubTracePath: [start, end],
|
|
303
319
|
axis,
|
|
@@ -324,10 +340,11 @@ export class InlineNetLabelSolver extends BaseSolver {
|
|
|
324
340
|
|
|
325
341
|
const height =
|
|
326
342
|
connection.inlineNetLabelHeight ?? DEFAULT_INLINE_NET_LABEL_HEIGHT
|
|
343
|
+
const netLabelText = connection.netLabelText?.trim() || undefined
|
|
327
344
|
const width =
|
|
328
345
|
connection.inlineNetLabelWidth ??
|
|
329
346
|
connection.netLabelWidth ??
|
|
330
|
-
estimateInlineNetLabelWidth(connection.netId!, height)
|
|
347
|
+
estimateInlineNetLabelWidth(netLabelText ?? connection.netId!, height)
|
|
331
348
|
|
|
332
349
|
const offset = height / 2 + INLINE_NET_LABEL_TRACE_MARGIN
|
|
333
350
|
|
|
@@ -385,6 +402,7 @@ export class InlineNetLabelSolver extends BaseSolver {
|
|
|
385
402
|
return {
|
|
386
403
|
globalConnNetId: trace.globalConnNetId,
|
|
387
404
|
netId: connection.netId,
|
|
405
|
+
netLabelText,
|
|
388
406
|
mspPairId: trace.mspPairId,
|
|
389
407
|
pinIds: [...connection.pinIds],
|
|
390
408
|
axis: segment.axis,
|
|
@@ -405,6 +423,7 @@ export class InlineNetLabelSolver extends BaseSolver {
|
|
|
405
423
|
const spanPlacement = this.computeSpanPlacement({
|
|
406
424
|
trace,
|
|
407
425
|
connection,
|
|
426
|
+
netLabelText,
|
|
408
427
|
width,
|
|
409
428
|
height,
|
|
410
429
|
offset,
|
|
@@ -425,12 +444,14 @@ export class InlineNetLabelSolver extends BaseSolver {
|
|
|
425
444
|
private computeSpanPlacement({
|
|
426
445
|
trace,
|
|
427
446
|
connection,
|
|
447
|
+
netLabelText,
|
|
428
448
|
width,
|
|
429
449
|
height,
|
|
430
450
|
offset,
|
|
431
451
|
}: {
|
|
432
452
|
trace: SolvedTracePath
|
|
433
453
|
connection: InlineEligibleConnection
|
|
454
|
+
netLabelText?: string
|
|
434
455
|
width: number
|
|
435
456
|
height: number
|
|
436
457
|
offset: number
|
|
@@ -521,6 +542,7 @@ export class InlineNetLabelSolver extends BaseSolver {
|
|
|
521
542
|
return {
|
|
522
543
|
globalConnNetId: trace.globalConnNetId,
|
|
523
544
|
netId: connection.netId,
|
|
545
|
+
netLabelText,
|
|
524
546
|
mspPairId: trace.mspPairId,
|
|
525
547
|
pinIds: [...connection.pinIds],
|
|
526
548
|
axis,
|
|
@@ -691,7 +713,7 @@ export class InlineNetLabelSolver extends BaseSolver {
|
|
|
691
713
|
? -inlineLabel.width / 2
|
|
692
714
|
: inlineLabel.width / 2)
|
|
693
715
|
: inlineLabel.center.y,
|
|
694
|
-
text: inlineLabel.netId ?? "",
|
|
716
|
+
text: inlineLabel.netLabelText ?? inlineLabel.netId ?? "",
|
|
695
717
|
color: "green",
|
|
696
718
|
fontSize: inlineLabel.height,
|
|
697
719
|
anchorSide: inlineLabel.stubTracePath
|
|
@@ -707,7 +729,7 @@ export class InlineNetLabelSolver extends BaseSolver {
|
|
|
707
729
|
x: inlineLabel.anchorPoint.x,
|
|
708
730
|
y: inlineLabel.anchorPoint.y,
|
|
709
731
|
color: "green",
|
|
710
|
-
label: `inline anchor\n${inlineLabel.netId}`,
|
|
732
|
+
label: `inline anchor\n${inlineLabel.netLabelText ?? inlineLabel.netId}`,
|
|
711
733
|
})
|
|
712
734
|
}
|
|
713
735
|
|
|
@@ -777,3 +799,90 @@ const doesPathIntersectBounds = (path: Point[], bounds: Bounds): boolean => {
|
|
|
777
799
|
}
|
|
778
800
|
return false
|
|
779
801
|
}
|
|
802
|
+
|
|
803
|
+
const GEOMETRY_EPSILON = 1e-6
|
|
804
|
+
|
|
805
|
+
/**
|
|
806
|
+
* Shortens an axis-aligned terminal stub before the first unrelated trace.
|
|
807
|
+
* Coordinates are schematic-world millimetres with +x right and +y up.
|
|
808
|
+
*/
|
|
809
|
+
const getCollisionLimitedTerminalStubEnd = ({
|
|
810
|
+
start,
|
|
811
|
+
intendedEnd,
|
|
812
|
+
minimumLength,
|
|
813
|
+
traces,
|
|
814
|
+
ownGlobalConnNetId,
|
|
815
|
+
}: {
|
|
816
|
+
start: Point
|
|
817
|
+
intendedEnd: Point
|
|
818
|
+
minimumLength: number
|
|
819
|
+
traces: SolvedTracePath[]
|
|
820
|
+
ownGlobalConnNetId: string
|
|
821
|
+
}): Point | null => {
|
|
822
|
+
const isHorizontal =
|
|
823
|
+
Math.abs(intendedEnd.x - start.x) >= Math.abs(intendedEnd.y - start.y)
|
|
824
|
+
const alongAxis = isHorizontal ? "x" : "y"
|
|
825
|
+
const acrossAxis = isHorizontal ? "y" : "x"
|
|
826
|
+
const direction = Math.sign(intendedEnd[alongAxis] - start[alongAxis]) || 1
|
|
827
|
+
const intendedLength = Math.abs(intendedEnd[alongAxis] - start[alongAxis])
|
|
828
|
+
let availableLength = intendedLength
|
|
829
|
+
|
|
830
|
+
for (const trace of traces) {
|
|
831
|
+
if (trace.globalConnNetId === ownGlobalConnNetId) continue
|
|
832
|
+
|
|
833
|
+
for (
|
|
834
|
+
let segmentIndex = 0;
|
|
835
|
+
segmentIndex < trace.tracePath.length - 1;
|
|
836
|
+
segmentIndex++
|
|
837
|
+
) {
|
|
838
|
+
const segmentStart = trace.tracePath[segmentIndex]!
|
|
839
|
+
const segmentEnd = trace.tracePath[segmentIndex + 1]!
|
|
840
|
+
const startAlong =
|
|
841
|
+
(segmentStart[alongAxis] - start[alongAxis]) * direction
|
|
842
|
+
const endAlong = (segmentEnd[alongAxis] - start[alongAxis]) * direction
|
|
843
|
+
const startAcross = segmentStart[acrossAxis] - start[acrossAxis]
|
|
844
|
+
const endAcross = segmentEnd[acrossAxis] - start[acrossAxis]
|
|
845
|
+
const minAlong = Math.min(startAlong, endAlong)
|
|
846
|
+
const maxAlong = Math.max(startAlong, endAlong)
|
|
847
|
+
const minAcross = Math.min(startAcross, endAcross)
|
|
848
|
+
const maxAcross = Math.max(startAcross, endAcross)
|
|
849
|
+
|
|
850
|
+
let collisionDistance: number | undefined
|
|
851
|
+
const isCollinear =
|
|
852
|
+
Math.abs(startAcross) <= GEOMETRY_EPSILON &&
|
|
853
|
+
Math.abs(endAcross) <= GEOMETRY_EPSILON
|
|
854
|
+
if (
|
|
855
|
+
isCollinear &&
|
|
856
|
+
maxAlong >= -GEOMETRY_EPSILON &&
|
|
857
|
+
minAlong <= intendedLength + GEOMETRY_EPSILON
|
|
858
|
+
) {
|
|
859
|
+
collisionDistance = Math.max(0, minAlong)
|
|
860
|
+
} else {
|
|
861
|
+
const crossesStubAxis =
|
|
862
|
+
minAcross <= GEOMETRY_EPSILON && maxAcross >= -GEOMETRY_EPSILON
|
|
863
|
+
const perpendicularAlong = (startAlong + endAlong) / 2
|
|
864
|
+
if (
|
|
865
|
+
crossesStubAxis &&
|
|
866
|
+
Math.abs(startAlong - endAlong) <= GEOMETRY_EPSILON &&
|
|
867
|
+
perpendicularAlong >= -GEOMETRY_EPSILON &&
|
|
868
|
+
perpendicularAlong <= intendedLength + GEOMETRY_EPSILON
|
|
869
|
+
) {
|
|
870
|
+
collisionDistance = Math.max(0, perpendicularAlong)
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
if (collisionDistance !== undefined) {
|
|
875
|
+
availableLength = Math.min(
|
|
876
|
+
availableLength,
|
|
877
|
+
collisionDistance - INLINE_NET_LABEL_STUB_TRACE_CLEARANCE,
|
|
878
|
+
)
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
if (availableLength + GEOMETRY_EPSILON < minimumLength) return null
|
|
884
|
+
|
|
885
|
+
return isHorizontal
|
|
886
|
+
? { x: start.x + direction * availableLength, y: start.y }
|
|
887
|
+
: { x: start.x, y: start.y + direction * availableLength }
|
|
888
|
+
}
|