master
Colby Knox Fix #133 (outline box from arcs and circles; ring courtyards: 2-degree sampling, interior probes), #130 (KICAD10_3RD_PA… f7d1e2b 15d ago
//! Wiki #133: concentric ring courtyards (two F.CrtYd circles each, an annulus) do not overlap, and a
//! board edge drawn as one large arc bounds the outline by its real extent.
use kicad_core::{pcb, placement};

fn ring(reference: &str, d_in: f64, d_out: f64) -> String {
    format!("(footprint \"x:{reference}\" (layer \"F.Cu\") (at 100 100) (property \"Reference\" \"{reference}\")\
        (fp_circle (center 0 0) (end {} 0) (layer \"F.CrtYd\") (stroke (width 0.05)))\
        (fp_circle (center 0 0) (end {} 0) (layer \"F.CrtYd\") (stroke (width 0.05))))", d_in / 2.0, d_out / 2.0)
}

#[test]
fn nested_ring_courtyards_do_not_overlap() {
    // the sensor from the report: electrodes and guards, all on one centre
    let fps = [ring("E2", 23.0, 31.95), ring("G2", 43.8, 47.7), ring("E4", 48.0, 56.95), ring("G3", 57.25, 59.25)].concat();
    let text = format!("(kicad_pcb (version 20241229) (layers (0 \"F.Cu\" signal)) {fps})");
    let board = pcb::parse_pcb_text(&text, "t.kicad_pcb").unwrap();
    let o = placement::overlaps(&placement::placements(&board));
    assert!(o.is_empty(), "{o:?}");
}

#[test]
fn a_large_edge_arc_bounds_the_outline_by_its_bulge() {
    // a 146 mm ring edge drawn as one arc of about 340 degrees: start and end low, mid at the top
    let r = 73.0_f64;
    let (cx, cy) = (100.0, 110.0);
    let a = |deg: f64| (cx + r * deg.to_radians().cos(), cy + r * deg.to_radians().sin());
    let (s, e, m) = (a(100.0), a(80.0), a(270.0));
    let text = format!("(kicad_pcb (version 20241229) (layers (0 \"F.Cu\" signal) (25 \"Edge.Cuts\" user))\
        (gr_arc (start {} {}) (mid {} {}) (end {} {}) (layer \"Edge.Cuts\") (stroke (width 0.1)))\
        (gr_line (start {} {}) (end {} {}) (layer \"Edge.Cuts\") (stroke (width 0.1)))\
        (gr_circle (center {cx} {cy}) (end {} {cy}) (layer \"Edge.Cuts\") (stroke (width 0.1))))",
        s.0, s.1, m.0, m.1, e.0, e.1, e.0, e.1, s.0, s.1, cx + 22.5);
    let board = pcb::parse_pcb_text(&text, "t.kicad_pcb").unwrap();
    let o = placement::outline(&board).unwrap();
    assert!((o.min_x - (cx - r)).abs() < 0.01 && (o.max_x - (cx + r)).abs() < 0.01, "{o:?}");
    assert!((o.min_y - (cy - r)).abs() < 0.01, "{o:?}");
}