← Commit history

1.0.12: 1.0.12: footprint-only lint stops blaming a missing kicad-cli (wiki #103), and Freerouting wires that come back under the board minimum are widened to the net class with a count (wiki #93).

John Lauer ·56c4aeae98 ·1mo ago ·parent 3328e86
4 files changed +45−5
rust/Cargo.lock+3−3
@@ -244,7 +244,7 @@ dependencies = [  [[package]] name = "kicad-bridge"-version = "1.0.11"+version = "1.0.12" dependencies = [  "kicad-core",  "kicad-platform",@@ -255,7 +255,7 @@ dependencies = [  [[package]] name = "kicad-core"-version = "1.0.11"+version = "1.0.12" dependencies = [  "kicad-ipc-rs",  "kicad-platform",@@ -281,7 +281,7 @@ dependencies = [  [[package]] name = "kicad-platform"-version = "1.0.11"+version = "1.0.12" dependencies = [  "serde",  "serde_json",
rust/Cargo.toml+1−1
@@ -3,7 +3,7 @@ resolver = "2" members = ["crates/*"]  [workspace.package]-version = "1.0.11"+version = "1.0.12" edition = "2021" license = "MIT" publish = false
rust/crates/kicad-core/src/dsn.rs+31−1
@@ -1064,6 +1064,8 @@ pub struct NetCopper {     /// Session items identical to copper already on the board (protected wiring echoed back).     #[serde(rename = "skippedExisting")]     pub skipped_existing: usize,+    /// segments widened to the net class minimum because the router returned them thinner (wiki #93)+    pub widened: usize, }  fn same_xy(a: [f64; 2], b: [f64; 2]) -> bool {@@ -1107,7 +1109,13 @@ pub fn copper_for(session: &Session, board: &Board, nets: Option<&[String]>, rul                 out[i].skipped_existing += 1;                 continue;             }-            out[i].segments.push(PlanSegment { start: a, end: b, layer: w.layer.clone(), width: w.width });+            // wiki #93: Freerouting hands back widths a hair under what the DSN asked for+            // (0.1874 where the class says 0.2), and KiCad's DRC then calls every one of them a+            // track_width error. The class width is already floored at the board minimum, so a+            // returned wire never lands thinner than the board allows; we count what we widened.+            let (_, class_w, _, _) = rules.class_for(&w.net);+            let width = if w.width + 1e-6 < class_w { out[i].widened += 1; class_w } else { w.width };+            out[i].segments.push(PlanSegment { start: a, end: b, layer: w.layer.clone(), width });         }     }     for v in &session.vias {@@ -1373,6 +1381,28 @@ mod tests {         assert!(copper_for(&s, &board2, Some(&["NET_1".into()]), &Rules::default()).is_empty());     } +    #[test]+    fn router_wire_thinner_than_the_class_is_widened_to_it() {+        // wiki #93: Freerouting answers 0.1874 mm where the DSN asked for the class width, and+        // KiCad's DRC calls every such segment a track_width error. The applier widens it back.+        let (_, board) = fixture();+        let thin = Session {+            unit: "um".into(),+            resolution: 10.0,+            nets: vec!["NET_3".into()],+            wires: vec![+                SesWire { net: "NET_3".into(), layer: "F.Cu".into(), width: 0.1874, points: vec![[105.0, 95.0], [112.0, 95.0]] },+                SesWire { net: "NET_3".into(), layer: "F.Cu".into(), width: 0.25, points: vec![[112.0, 95.0], [138.0, 95.0]] },+            ],+            ..Default::default()+        };+        let copper = copper_for(&thin, &board, None, &Rules::default());+        assert_eq!(copper.len(), 1);+        assert_eq!(copper[0].widened, 1, "only the thin one is widened: {copper:?}");+        assert_eq!(copper[0].segments[0].width, Rules::default().track_width);+        assert_eq!(copper[0].segments[1].width, 0.25, "a wire at the class width is left alone");+    }+     #[test]     fn specctra_tokenizer_handles_string_quote_and_bad_input() {         let sx = parse_specctra("(a (string_quote \") (b \"x y\") c)").unwrap();
rust/crates/kicad-core/src/lint.rs+10
@@ -938,6 +938,16 @@ pub fn library_hint(              kicad_install_library / kicad_install_symbol / kicad_install_footprint.",             kp_ok.len()         )+    } else if kicad_verdicts.is_empty() && footprint_count > 0 && symbol_count == 0 {+        // wiki #103: footprints alone. kicad-cli lints SYMBOL libraries; it has no footprint+        // verdict, so saying "kicad-cli not found" blames a missing tool for a gap that is by+        // design, and sends the caller hunting for an executable that is right there.+        format!(+            "✅ {footprint_count} footprint(s) balanced by the BRIDGE's reader, \+             format version(s) {versions_s}. KiCad's own parser has no footprint verdict to give \+             (kicad-cli checks symbol libraries), so footprints are a structural check by design, \+             not a missing tool. Safe to install via kicad_install_footprint."+        )     } else {         format!(             "✅ {symbol_count} symbol(s) + {footprint_count} footprint(s) balanced by the BRIDGE's reader, \