Skip to content

Bug: a circular courtyard reads as no courtyard, so mounting holes and test points land on other parts #273

Open

Description

@JeffMboya

What were you trying to achieve?

Add four M2.5 mounting holes, two fiducials and a handful of test points to the
Class-A boards, so each one can be mounted, assembled and brought up.

What are the expected results?

The placer reserves each part's real courtyard, and kicad-cli pcb drc
reports no courtyards_overlap.

What are the received results?

courtyards_overlap on every routed run, always between a mechanical part and
whatever the placer put beside it. The first run of the standalone
protected_power_entry reported four, every one a mounting hole:

error courtyards_overlap | Footprint J2, Footprint H1
error courtyards_overlap | Footprint C10, Footprint H3
error courtyards_overlap | Footprint J1, Footprint H1
error courtyards_overlap | Footprint H1, Footprint D2

H1 alone collided with three different parts, which is what a too-small
reservation looks like to a packing algorithm. On the routed board TP2 sits
at (15.75, 37.73) and H3 at (17.25, 40.73) — 3.354 mm between centres, where
the two courtyards need 4.0 mm.

Steps To Reproduce

  1. Put mounting_hole_m2_5, fiducial_1mm or testpoint_pad_1_5 on a board
    beside ordinary parts.
  2. Export and route.
  3. kicad-cli pcb drc reports the mechanical part overlapping its neighbour.

In what environment did you encounter the issue?

KiCad 10.0.6, KiCadRoutingTools caad45c, synth from main at dddda6f.

Additional information you deem important

Two bugs, one symptom. Read in order:

kicad_footprint_loader::courtyard_rect matches (fp_rect and (fp_line
blocks on F.CrtYd and nothing else. All three of these footprints draw their
courtyard as a single fp_circle:

Footprint F.CrtYd geometry Across
MountingHole:MountingHole_2.5mm fp_circle r 2.75 5.5 mm
TestPoint:TestPoint_Pad_D1.5mm fp_circle r 1.25 2.5 mm
Fiducial:Fiducial_1mm_Mask2mm fp_circle r 1.25 2.5 mm

So courtyard_rect returns None for each of them, and
pcb_courtyard_geometry_for_part falls through to its second branch —
crates/synth-layout/src/lib.rs:3368:

if let Some(dim) = part.footprint_dimensions.as_ref() {
    return ((0.0, 0.0), (dim.width_mm, dim.height_mm));
}

which drops courtyard_margin_mm. A mounting hole therefore reserves
2.5 × 2.5 mm — the hole — against a 5.5 mm courtyard, and its neighbours are
packed 1.5 mm a side too close. The DRC that follows is correct.

That the margin is dropped was confirmed the hard way: raising
mounting_hole_m2_5's declared margin from 0.25 mm to 1.5 mm produced a
byte-identical placement and the same overlaps, because nothing reads it.

The narrow fix is to read the circle: a (fp_circle ...) on F.CrtYd
contributes the bbox of center ± r. That is strictly additive — a footprint
that already draws a rectangle is unaffected — and it fixes these three parts
from the geometry rather than from a transcribed number. It is in the Class-A
stack, with tests over a footprint's text so the parsing is checkable without
an installed library.

The second bug is left open here: the fallback should still honour
courtyard_margin_mm, because it is the branch every footprint with an
fp_poly courtyard takes, and silently reserving the body instead of the
courtyard is the same mistake one level down. That change moves placement for
many more parts than these three, so it wants its own measurement rather than
riding along.

Found while making the Class-A boards standalone: #269, #268, #271. The
Class-C case 4 board carries the same three parts.

Activity

  1. changed the title [-]Bug: a footprint whose courtyard is a circle reserves no area, so mounting holes land on other parts[/-] [+]Bug: three mechanical parts declare the hole diameter as their courtyard, so the placer packs 2.5 mm too close[/+] on Oct 23, 2026
  2. changed the title [-]Bug: three mechanical parts declare the hole diameter as their courtyard, so the placer packs 2.5 mm too close[/-] [+]Bug: a circular courtyard reads as no courtyard, so mounting holes and test points land on other parts[/+] on Oct 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions