Multi-layer crossing minimization for PCB connector pin assignment. Detects trace crossings in SKiDL-generated KiCad netlists and computes optimal pin orderings for single-layer routing using Sugiyama-style barycenter sweep.
pip install pcb-crossing-optimizer
After installation, the pcb-crossing-optimizer command is available on your PATH.
The tool has two subcommands: analyze (default) and plan-footprint.
Analyze crossings between component layers. This is the original behavior and remains the default when no subcommand is given.
pcb-crossing-optimizer [analyze] <netlist.net> --layers "L0_refs | L1_refs | L2_refs" --reorderable REF [REF ...] [--exclude REF:PIN ...] [--json] [--quiet]
Analyze the microSD breakout with passives in the middle layer:
pcb-crossing-optimizer examples/microsd_breakout.net --layers "J1 | R1,R2,C1 | J2" --reorderable J2 --exclude J1:SH
Simple two-connector case (just use two layers):
pcb-crossing-optimizer examples/i2c_breakout.net --layers "J1 | J2" --reorderable J2
JSON output for tooling integration:
pcb-crossing-optimizer examples/i2c_breakout.net --layers "J1 | J2" --reorderable J2 --json
Quiet mode for CI (exit code 0 = no crossings, 1 = crossings remain):
pcb-crossing-optimizer examples/i2c_breakout.net --layers "J1 | J2" --reorderable J2 --quiet
Compute an optimal pin map for a custom footprint. Given a target component (whose footprint you are designing), fixed anchor components, and optional pin locks, it runs the crossing sweep and produces a complete pin-to-net assignment proposal.
pcb-crossing-optimizer plan-footprint <netlist.net> \
--target J1 \
--anchors "J2,U1 | R1,R2,R3,C1" \
--lock 1=NC 2=NC 3=GND_EARLY_A \
--unmatched end \
--exclude-nets GND \
[--json] [--quiet]
Options:
--target REF: Component whose footprint is being designed--anchors "...": Fixed components organized in layers separated by|--lock PIN=NET: Lock specific pins to nets (usePIN=NCfor no-connect)--unmatched start|end|split: Where to place pins with no anchor connections (default:end)--exclude-nets NET [NET ...]: Nets to exclude from analysis (e.g. ground pours)
Nets spanning non-adjacent layers (e.g., J1 to J2 through a passive layer) are handled automatically via virtual pass-through nodes.
- Parses a KiCad .net file (S-expression format generated by SKiDL)
- Extracts pin-to-net connectivity for specified components
- Sugiyama-style barycenter sweep across all layers:
- Inserts virtual nodes for long edges spanning non-adjacent layers
- Reorders both pins within reorderable components and components within layers
- Iterates forward/backward sweeps until convergence
- Reports current crossings, recommended reordering, and remaining crossings
src/crossing_analyzer.py Core logic + CLI
tests/ pytest tests
examples/ Sample netlists for testing
pip install pytest
pytest -v
- Passive placement optimizer (assign positions to resistors/caps in routing channel)
- F.Cu/B.Cu layer assignment for unavoidable crossings
- Migration to skidl-vscode extension (core/crossing.py + MCP tool + VS Code command)
The PyPI package name is pcb-crossing-optimizer, but the importable module is crossing_analyzer:
from crossing_analyzer import sweep_optimize, PinColumn, format_multilayer_report