app
KiCad - the KiCad Bridge
Public Made by Adomby adom
Reference implementation of the KiCad bridge: multi-instance Python server, forward path via kicad-cli, reverse path via in-process plugin. Most complex of the three bundled bridges.
← Commit history
ESC placement fixture: machine pins and contacts stay in place and locked (molecule interface), keep-refs option
1 file changed
+23−4
tools/make_placement_fixture.py+23−4@@ -316,7 +316,7 @@ def at_edit(at_node, x, y, angle, keep_angle_atom): return (at_node.start, at_node.end, "(" + " ".join(parts) + ")") -def plan_edits(text, root, park, gap, margin, keep_teardrops, strip_zones=False, strip_graphics=False):+def plan_edits(text, root, park, gap, margin, keep_teardrops, strip_zones=False, strip_graphics=False, keep_refs=None): """All edits for one copy. Returns (edits, summary).""" edits = [] removed = {"segments": 0, "vias": 0, "arcs": 0, "filledPolygons": 0, "teardropZones": 0, "groupsDropped": 0, "groupMembersDropped": 0}@@ -374,6 +374,21 @@ def plan_edits(text, root, park, gap, margin, keep_teardrops, strip_zones=False, parked = 0 parking = None fps = root.find_all("footprint")+ import re as _re+ keep_re = _re.compile(keep_refs) if keep_refs else None+ kept_refs = []+ if keep_re:+ for fp in fps:+ ref = reference_of(fp)+ if keep_re.fullmatch(ref or ""):+ kept_refs.append(ref)+ if fp.find("locked") is None:+ # insert (locked yes) right after the layer line of the footprint+ layer = fp.find("layer")+ if layer is not None:+ st, en = line_span(text, layer)+ edits.append((en, en, "\t\t(locked yes)\n"))+ fps = [fp for fp in fps if not keep_re.fullmatch(reference_of(fp) or "")] if park: cells = [] for fp in fps:@@ -420,8 +435,11 @@ def plan_edits(text, root, park, gap, margin, keep_teardrops, strip_zones=False, summary = { "footprints": len(fps), "footprintsParked": parked, "removed": removed, "outline": {"minX": outline[0], "minY": outline[1], "maxX": outline[2], "maxY": outline[3]},++ summary["keptInPlace"] = kept_refs "parking": None if parking is None else {"minX": round(parking[0], 3), "minY": round(parking[1], 3), "maxX": round(parking[2], 3), "maxY": round(parking[3], 3)}, }+ summary["keptInPlace"] = kept_refs return edits, summary @@ -440,13 +458,13 @@ def apply_edits(text, edits): return "".join(out) -def make(text, park, gap=GAP_MM, margin=MARGIN_MM, keep_teardrops=False, strip_zones=False, strip_graphics=False):+def make(text, park, gap=GAP_MM, margin=MARGIN_MM, keep_teardrops=False, strip_zones=False, strip_graphics=False, keep_refs=None): root = parse(text) if root.tag != "kicad_pcb": raise ValueError("not a kicad_pcb file") if outline_bbox(root) is None: raise ValueError("no Edge.Cuts outline found; refusing (nothing to park relative to)")- edits, summary = plan_edits(text, root, park, gap, margin, keep_teardrops, strip_zones, strip_graphics)+ edits, summary = plan_edits(text, root, park, gap, margin, keep_teardrops, strip_zones, strip_graphics, keep_refs) return apply_edits(text, edits), summary @@ -458,6 +476,7 @@ def main(argv=None): ap.add_argument("--margin", type=float, default=MARGIN_MM, help="gap between the outline and the parking grid, mm") ap.add_argument("--keep-teardrops", action="store_true", help="keep teardrop zones (generated copper) instead of dropping them") ap.add_argument("--strip-zones", action="store_true", help="drop every zone (the demo board starts with no copper pours at all)")+ ap.add_argument("--keep-refs", help="regex of references that stay where they are and get locked (a molecule's machine pins and contacts, e.g. 'M[CP]\\d+')") ap.add_argument("--strip-graphics", action="store_true", help="drop board-level graphics and text on every layer except Edge.Cuts (labels and logos that describe the original layout)") ap.add_argument("--self-test", action="store_true") a = ap.parse_args(argv)@@ -474,7 +493,7 @@ def main(argv=None): stem = src.name[: -len(".kicad_pcb")] if src.name.endswith(".kicad_pcb") else src.stem report = {"source": str(src), "outputs": {}} for kind, park in (("unplaced", True), ("unrouted", False)):- new_text, summary = make(text, park, a.gap, a.margin, a.keep_teardrops, a.strip_zones, a.strip_graphics)+ new_text, summary = make(text, park, a.gap, a.margin, a.keep_teardrops, a.strip_zones, a.strip_graphics, a.keep_refs) dest = out_dir / ("%s-%s.kicad_pcb" % (stem, kind)) with open(dest, "w", encoding="utf-8", newline="") as f: f.write(new_text)