← Commit history

0.2.31 source: board_shape uses the proven outline pattern, nil-guarded

John Lauer ·3028ea6825 ·1mo ago ·parent 50c0977
6 files changed +35−34
bridge-rs/Cargo.lock+1−1
@@ -10,7 +10,7 @@ checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"  [[package]] name = "altium-bridge"-version = "0.2.30"+version = "0.2.31" dependencies = [  "getrandom",  "serde",
bridge-rs/Cargo.toml+1−1
@@ -1,6 +1,6 @@ [package] name = "altium-bridge"-version = "0.2.30"+version = "0.2.31" edition = "2021" description = "Adom altium-bridge — the bridge process, in Rust. Calls ab's verbs for the desktop; speaks file IPC to the resident DelphiScript agent inside Altium." license = "MIT"
bridge-rs/src/main.rs+1−1
@@ -26,7 +26,7 @@ mod win32; use std::time::Instant; use tiny_http::{Header, Method, Response, Server}; -pub const BRIDGE_VERSION: &str = "0.2.30";+pub const BRIDGE_VERSION: &str = "0.2.31";  fn json_response(status: u16, body: &serde_json::Value) -> Response<std::io::Cursor<Vec<u8>>> {     let data = serde_json::to_vec(body).unwrap_or_else(|_| b"{}".to_vec());
bridge.json+1−1
@@ -2,7 +2,7 @@   "manifest_version": 1,   "name": "altium",   "displayName": "Altium Designer",-  "version": "0.2.30",+  "version": "0.2.31",   "description": "Drive Altium Designer from Adom: a resident DelphiScript agent (eval + the 1,100-command process launcher), the X2 -R command line, UIA over the VCL shell, dialogs by PID, screenshots of every Altium window, and Altium 365.",   "homepage": "https://wiki.adom.inc/adom/altium-bridge",   "docs": "https://wiki.adom.inc/adom/altium-bridge",
page.json+1−1
@@ -140,4 +140,4 @@     "skills/altium-wiki-import/SKILL.md",     "uninstall.sh"   ]-}\ No newline at end of file+}
src/agent/AdomAgent.pas.tmpl+30−29
@@ -3278,16 +3278,20 @@ End;  { ------------------------------------------------------------ board_shape --- } -{ Redefine the CURRENT board shape as a wMm x hMm rectangle at (x0Mm,y0Mm) using-  the editor process PCB:PlaceBoardOutline Mode=BOARDOUTLINE_FROM_SEL_PRIMS on-  four temporary selected tracks (BoardOutline.PointCount/Segments is a silent-  no-op in this engine, measured 2026-08-30). }+{ Redefine the CURRENT board shape as a wMm x hMm rectangle at (x0Mm,y0Mm).+  Until 0.2.31 this drew four temporary tracks and ran the editor process+  PCB:PlaceBoardOutline (Mode=BOARDOUTLINE_FROM_SEL_PRIMS), then read+  Board.BoardOutline.BoundingRectangle with NO nil guard. On AD 26.10.1 and on Altium Develop the+  process left no outline, the read raised on a nil object, and the script parked on a breakpoint+  with no error box (found by the verb battery on two builds, 2026-09-20). It now uses the pattern+  CmdTestBoard has always used and that renders correctly on every build: PointCount + Segments[]+  + Rebuild on the board's own outline, every access nil-guarded. } Function CmdBoardShape(Lines : TStringList) : String; Var     Board : IPCB_Board;-    T     : IPCB_Track;-    Trks  : Array[0..3] Of IPCB_Track;-    X0, Y0, X1, Y1, I : Integer;+    BO    : IPCB_BoardOutline;+    Seg   : TPolySegment;+    X0, Y0, X1, Y1 : Integer;     R : TCoordRect; Begin     Board := PCBServer.GetCurrentPCBBoard;@@ -3300,33 +3304,30 @@ Begin     Y0 := MMsToCoord(AdomFloat(Param(Lines, 'y0Mm')));     X1 := X0 + MMsToCoord(AdomFloat(Param(Lines, 'wMm')));     Y1 := Y0 + MMsToCoord(AdomFloat(Param(Lines, 'hMm')));-    PCBServer.PreProcess;-    For I := 0 To 3 Do+    If (X1 <= X0) Or (Y1 <= Y0) Then     Begin-        T := PCBServer.PCBObjectFactory(eTrackObject, eNoDimension, eCreate_Default);-        T.Layer := eMechanical1;-        T.Width := MMsToCoord(0.1);-        Case I Of-            0: Begin T.X1 := X0; T.Y1 := Y0; T.X2 := X1; T.Y2 := Y0; End;-            1: Begin T.X1 := X1; T.Y1 := Y0; T.X2 := X1; T.Y2 := Y1; End;-            2: Begin T.X1 := X1; T.Y1 := Y1; T.X2 := X0; T.Y2 := Y1; End;-            3: Begin T.X1 := X0; T.Y1 := Y1; T.X2 := X0; T.Y2 := Y0; End;-        End;-        Board.AddPCBObject(T);-        PCBServer.SendMessageToRobots(Board.I_ObjectAddress, c_Broadcast, PCBM_BoardRegisteration, T.I_ObjectAddress);-        Trks[I] := T;+        Result := '{' + JRaw('ok','false') + ',' + JStr('errorCode','bad_size') + ',' + JStr('error','wMm and hMm must both be greater than 0') + '}';+        Exit;+    End;+    BO := Board.BoardOutline;+    If BO = Nil Then+    Begin+        Result := '{' + JRaw('ok','false') + ',' + JStr('errorCode','no_board_outline') + ',' ++            JStr('error','this document has no board outline object (a PcbLib internal board has none); open a .PcbDoc') + '}';+        Exit;     End;-    PCBServer.PostProcess;-    Board.SelectedObjects_Clear;-    For I := 0 To 3 Do Trks[I].Selected := True;-    ResetParameters;-    AddStringParameter('Mode', 'BOARDOUTLINE_FROM_SEL_PRIMS');-    RunProcess('PCB:PlaceBoardOutline');     PCBServer.PreProcess;-    For I := 0 To 3 Do Board.RemovePCBObject(Trks[I]);+    BO.Invalidate;+    BO.PointCount := 4;+    Seg := BO.Segments[0]; Seg.vx := X0; Seg.vy := Y0; Seg.Kind := ePolySegmentLine; BO.Segments[0] := Seg;+    Seg := BO.Segments[1]; Seg.vx := X1; Seg.vy := Y0; Seg.Kind := ePolySegmentLine; BO.Segments[1] := Seg;+    Seg := BO.Segments[2]; Seg.vx := X1; Seg.vy := Y1; Seg.Kind := ePolySegmentLine; BO.Segments[2] := Seg;+    Seg := BO.Segments[3]; Seg.vx := X0; Seg.vy := Y1; Seg.Kind := ePolySegmentLine; BO.Segments[3] := Seg;+    BO.Rebuild;+    BO.Validate;     PCBServer.PostProcess;     Board.ViewManager_FullUpdate;-    R := Board.BoardOutline.BoundingRectangle;+    R := BO.BoundingRectangle;     Result := '{' + JRaw('ok','true') + ',' +         JRaw('outlineMil', '[' + IntToStr(Round(CoordToMils(R.Left))) + ',' + IntToStr(Round(CoordToMils(R.Bottom))) + ',' +              IntToStr(Round(CoordToMils(R.Right))) + ',' + IntToStr(Round(CoordToMils(R.Top))) + ']') + '}';