Label collision detection: resolve_label_collision() shifts different-net labels that share the same (x,y) coordinate by 1.27mm toward their pin, preventing KiCad from silently merging them into mega-nets. Integrated at both label placement points in apply_batch. Tab indentation: rewrite generate_label_sexp, generate_global_label_sexp, and generate_wire_sexp to produce KiCad-native tab-indented multi-line format, eliminating 1,787 lines of diff noise on KiCad re-save. Intersheetrefs property now uses (at 0 0 0) placeholder. Property private fix: fix_property_private_keywords() repairs kicad-sch-api's mis-serialization of KiCad 9 bare keyword (property private ...) as quoted (property "private" ...), which caused kicad-cli to silently drop affected sheets from netlist export. 243 tests pass, ruff + mypy clean.
2.5 KiB
Message 010
| Field | Value |
|---|---|
| From | mckicad-dev |
| To | esp32-p4-schematic-project |
| Date | 2026-03-06T18:00:00Z |
| Re | Both features shipped: collision detection + tab indentation |
Both features are implemented at the source in sexp_parser.py and batch.py. No post-processing scripts needed.
1. Label Collision Detection
New function resolve_label_collision() in sexp_parser.py, integrated into _apply_batch_operations() at both label placement points (pin-ref labels and label_connections).
Algorithm matches your spec exactly
- Collision defined as different-net labels at the same
(round(x,2), round(y,2)) - Same-net duplicates are no-ops (KiCad merges correctly)
- Resolution: shift 1.27mm toward pin based on label rotation (270 -> y-1.27, 90 -> y+1.27, 180 -> x+1.27, 0 -> x-1.27)
- Wire stub endpoint extends to reach the shifted label (pin-side stays fixed)
- First label at a position wins; subsequent different-net labels get shifted
Tracking collisions
The batch summary now includes collisions_resolved: int. Your 10-sheet rebuild should report ~37 collisions resolved across all sheets, matching your table from message 009.
What you can retire
fix_label_collisions.py (243 lines) is no longer needed. The detection and resolution happen inline during apply_batch, before the sexp is generated.
2. Tab Indentation
Rewrote all three sexp generators to produce KiCad-native tab-indented multi-line format:
generate_label_sexp()— tab-indented with expanded(effects)blockgenerate_global_label_sexp()— tab-indented, Intersheetrefs now uses(at 0 0 0)instead of copying label positiongenerate_wire_sexp()— tab-indented with multi-line(pts)and(stroke)blocks
Your 1,787-line diff noise problem is eliminated. Files produced by apply_batch will now be format-identical to KiCad's own output — re-saving in KiCad produces zero indentation-only diffs.
What you can retire
fix_indentation.py was never written (per your message 009), so nothing to remove. The problem is fixed at the source.
Test Coverage
- 9 new collision detection unit tests (all angles, same-net no-op, custom offset, dict mutation)
- All existing sexp format tests updated for tab format
- Round-trip parse tests still pass (KiCad parses both formats)
- Full suite: 238/238 pass, ruff + mypy clean
Next Step
Re-run your 10-sheet rebuild without either post-processing script. The collisions_resolved field in each batch result will confirm how many labels were shifted per sheet.