← Commit history

0.2.52 source (not yet released, needs signing): symbol_prims answers the drawn display mode's body (union of its rectangles), not the first rectangle of any mode. Verified live on AD 26.11.1

Colby Knox ·c6b509ac0e ·1d ago ·parent 2e737a4
3 files changed +26−7
CHANGELOG.md+2−3
@@ -1,9 +1,8 @@ # Changelog -## Unreleased-- **Library pins keep their electrical type.** `altium-symbol-modes` carries each KiCad pin type into the spec (a 10th field), and `build_symbol_modes` sets Altium's pin type from it: input, output, bidirectional (IO), tri-state (HiZ), open collector, open emitter, power in/out (Power), else Passive. Every pin used to be Passive, so Altium's ERC and AI Flow's pin-type check could not tell a power or output pin from a resistor's. `read_symbol` returns each pin's `electrical` (0 Input, 1 IO, 2 Output, 3 OpenCollector, 4 Passive, 5 HiZ, 6 OpenEmitter, 7 Power). Live on AD 26.11.1: the TPS54202's GND, SW and VIN read 7, FB and EN 0, BOOT 4.- ## 0.2.52 (2026-10-20)+- **`symbol_prims` answers the drawn mode's body.** `bodyRectMil` was the first rectangle found, which could belong to any display mode: the TPS54202's 10-mode symbol answered a wider mode's 1200 mil body for its 700 mil drawn body, and a capacitor answered one plate. It is now the union of the current display mode's rectangles (mode 0, the one a sheet draws).+- **Library pins keep their electrical type.** `altium-symbol-modes` carries each KiCad pin type into the spec (a 10th field), and `build_symbol_modes` sets Altium's pin type from it: input, output, bidirectional (IO), tri-state (HiZ), open collector, open emitter, power in/out (Power), else Passive. Every pin used to be Passive, so Altium's ERC and AI Flow's pin-type check could not tell a power or output pin from a resistor's. `read_symbol` returns each pin's `electrical` (0 Input, 1 IO, 2 Output, 3 OpenCollector, 4 Passive, 5 HiZ, 6 OpenEmitter, 7 Power). Live on AD 26.11.1: the TPS54202's GND, SW and VIN read 7, FB and EN 0, BOOT 4. - **Importing a part again replaces its 3D body instead of stacking a second one.** `add_body` (and the `step` of `import_part`, which calls it) added a new body every call and never removed the old one, and `normalize_bodies` then centred both on the pads: the AMPLH5030S inductor reached a board (2026-10-16) with the old model and the fixed one inside each other, repaired only by `remove_footprint`, a re-import and `PCB:UpdateFootprints`. The agent now deletes the footprint's existing 3D bodies before it adds the new one, the way the editor's Edit > Delete does (it selects exactly those bodies and runs `PCB:Clear`; `RemovePCBObject` left them in the stored footprint after save), how `build_symbol_modes` replaces a symbol of the same LibReference. It removes nothing until the new STEP has loaded, so a bad path keeps the old body. - The `add_body` reply says `replacedBodies` (also at the top level), `keptExisting`, `bodiesBefore`, `sameNameFootprints` and `bodiesNow`, and its `_hint` warns when bodies are still stacked or when several footprints share the name (only the first gets the body). `import_part`'s add_body step carries `replacedBodies`, `bodiesNow` and `sameNameFootprints`. - New `add_body` argument `keepExisting` (default false): add next to the existing bodies, for a deliberate second body.
bridge-rs/src/verbs.rs+1−1
@@ -143,7 +143,7 @@ fn describe() -> Value {             &["It really does halt the engine for a moment: do not run it while a user is mid-edit in Altium.",               "By design this is the SLOWEST verb in the catalog: it halts the engine, waits for the halt to be seen, recovers it and verifies by restarting the agent. Altium Designer Develop parks SILENTLY (no Error box), so the halt is only seen when the wait expires — measured 18 s to over 60 s on the same machine. Its budget is 180 s for that reason; a timeout here means the safety net is broken, not that it was slow."], json!({})),         verb_doc("symbol_prims", "Read a SchLib component's drawing: primitive counts by kind, body rectangle, polyline bounding box, display mode and the footprint models. Read-only, use it to verify add_symbol_art / set_models.",-            json!({"libraryPath": "path (.SchLib)", "symbolName": "string", "models": "bool, default false (the model walk halts the engine on some builds)"}), json!({"pins": "int", "rectangles": "int", "lines": "int", "polylines": "int", "bodyRectMil": "[..]", "polyBboxMil": "[..]", "models": "[\"PCBLIB:NAME\"]"}), 60,+            json!({"libraryPath": "path (.SchLib)", "symbolName": "string", "models": "bool, default false (the model walk halts the engine on some builds)"}), json!({"pins": "int", "rectangles": "int", "lines": "int", "polylines": "int", "bodyRectMil": "[l, b, r, t] - the union of the current display mode's rectangles (mode 0, as a sheet draws it)", "polyBboxMil": "[..]", "models": "[\"PCBLIB:NAME\"]"}), 60,             "polylines should equal what add_symbol_art reported and polyBboxMil should sit inside bodyRectMil.", &["add_symbol_art", "set_models", "read_symbol"], &[], json!({})),         verb_doc("set_models", "Replace every footprint model on a SchLib component with ONE PCBLIB model (set_params footprint and add_models APPEND, which is how a symbol ends up with two).",             json!({"libraryPath": "path (.SchLib)", "symbolName": "string", "footprint": "string (PcbLib footprint name)"}), json!({"removed": "int", "footprint": "string"}), 60,
src/agent/AdomAgent.pas.tmpl+23−3
@@ -1790,6 +1790,7 @@ End;  Function CmdSymbolPrims(Lines : TStringList) : String; Var+    AnyR0 : Boolean;     SLib  : ISch_Lib;     Iter  : ISch_Iterator;     Comp  : ISch_Component;@@ -1824,7 +1825,7 @@ Begin         Exit;     End;     NPin := 0; NRect := 0; NLine := 0; NPoly := 0; NOther := 0;-    AnyP := False; AnyR := False;+    AnyP := False; AnyR := False; AnyR0 := False;     PX0 := 0; PY0 := 0; PX1 := 0; PY1 := 0; RX0 := 0; RY0 := 0; RX1 := 0; RY1 := 0;     Iter := Comp.SchIterator_Create;     Prim := Iter.FirstSchObject;@@ -1834,9 +1835,28 @@ Begin         Else If Prim.ObjectID = eRectangle Then         Begin             NRect := NRect + 1;-            If Not AnyR Then+            { the body of the mode the symbol shows (the sheet draws mode 0): the union of that+              mode's rectangles (a capacitor's two plates are two). The first rectangle found+              could be any mode's: a 10-mode symbol answered a wider mode's body. }+            R := Prim.BoundingRectangle;+            If Prim.OwnerPartDisplayMode = Comp.DisplayMode Then+            Begin+                If Not AnyR0 Then+                Begin+                    RX0 := Round(CoordToMils(R.Left)); RY0 := Round(CoordToMils(R.Bottom));+                    RX1 := Round(CoordToMils(R.Right)); RY1 := Round(CoordToMils(R.Top));+                End+                Else+                Begin+                    If Round(CoordToMils(R.Left)) < RX0 Then RX0 := Round(CoordToMils(R.Left));+                    If Round(CoordToMils(R.Bottom)) < RY0 Then RY0 := Round(CoordToMils(R.Bottom));+                    If Round(CoordToMils(R.Right)) > RX1 Then RX1 := Round(CoordToMils(R.Right));+                    If Round(CoordToMils(R.Top)) > RY1 Then RY1 := Round(CoordToMils(R.Top));+                End;+                AnyR0 := True; AnyR := True;+            End+            Else If Not AnyR Then             Begin-                R := Prim.BoundingRectangle;                 RX0 := Round(CoordToMils(R.Left)); RY0 := Round(CoordToMils(R.Bottom));                 RX1 := Round(CoordToMils(R.Right)); RY1 := Round(CoordToMils(R.Top));                 AnyR := True;