← Commit history

ESC placement fixture: machine pins and contacts stay in place and locked (molecule interface), keep-refs option

John Lauer ·43aa9a9319 ·24d ago ·parent 73fb343
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)