Skip to content

Sub-mil coordinates for track/via/pad placement and the position getters - #31

Closed
bblacklock3 wants to merge 2 commits into
salitronic:mainfrom
bblacklock3:feat/submil-coordinates
Closed

bblacklock3 wants to merge 2 commits into
salitronic:mainfrom
bblacklock3:feat/submil-coordinates

Conversation

@bblacklock3

Copy link
Copy Markdown
Contributor

Placement coordinates were parsed with StrToIntDef, and the Utils.pas wrappers MilsToCoord / CoordToMils are Integer, so every placed or queried position was quantised to 1 mil (25.4 µm) although Altium's TCoord resolves 1/10000 mil. For scripted geometry that matters: on a generated coil trace with 0.09 mm chords the rounding is a ±18 µm vertex error and a visibly kinked trace, and copper exported through obj_query is capped at 1 mil.

This PR:

  • adds MilsToCoordF(Double) and CoordToMilsF -> Double next to the integer wrappers (which are untouched, so the other ~300 call sites are unaffected);
  • parses the coordinates of PCB_PlaceTrack, PCB_PlaceTracks, PCB_PlaceVia and PCB_PlacePad with StrToFloatDef and converts them with MilsToCoordF; widths, sizes and hole sizes stay integer mils;
  • returns X, Y, X1, Y1, X2, Y2 from the PCB property getter through FloatToJsonStr(CoordToMilsF(...)).

Compatibility: whole-mil positions still print as integers (FloatToStr(100) = '100'), so existing callers only see decimals where the copper actually has them. The placement responses echo the parsed doubles the same way.

Verified on Altium Designer 26.9.1: a track placed at 100.25,100.75,150.5,120.125 reads back with exactly those values; a 1475-track generated coil round-trips 0 missing / 0 extra within 0.01 mil.

Based on #30 (the Arc.LineWidth fix) because both touch PCBGeneric.pas; the two commits are independent otherwise.

🤖 Generated with Claude Code

bblacklock3 and others added 2 commits September 18, 2026 14:38
…getter

IPCB_Arc has no Width member, so obj_query with Width on an eArcObject raised a modal
'Undeclared identifier: Width' in the script engine before any Try/Except ran, which stopped
the polling loop until a human dismissed it and re-ran StartMCPServer. Reported from a live
board on 2026-09-14 while exporting coil copper.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…tion getters

The bridge parsed placement coordinates with StrToIntDef and the Utils.pas wrappers
MilsToCoord / CoordToMils are Integer, so every placed or queried position was quantised to
1 mil (25.4 um) although Altium's TCoord resolves 1/10000 mil. On a generated coil trace with
0.09 mm chords that is a +-18 um vertex error and a visibly kinked trace; for exports it caps
copper geometry at 1 mil.

Adds MilsToCoordF(Double) / CoordToMilsF -> Double next to the integer wrappers (nothing
else changes), parses the coordinates of PCB_PlaceTrack, PCB_PlaceTracks, PCB_PlaceVia and
PCB_PlacePad with StrToFloatDef, and returns X, Y, X1, Y1, X2, Y2 from the obj_query getter
through FloatToJsonStr(CoordToMilsF(...)). Whole-mil positions still print as integers
(FloatToStr(100) = '100'), so existing callers see decimals only where the copper has them.
Sizes, widths and hole sizes stay integer mils.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@salitronic

Copy link
Copy Markdown
Owner

Merged as 66e9e62, on top of #30.

Three things I checked before taking it, since all three would have been quiet failures:

  • Locale. StrToFloatDef and FloatToJsonStr are this repo's own wrappers rather than Delphi's, and both normalise the decimal separator, so a comma-decimal machine is fine. Using Delphi's directly here would have produced 100,25 in the JSON.
  • Declaration order. Utils.pas is second in build.py's concatenation list and PCBGeneric.pas and PCB.pas are sixth and seventh, so MilsToCoordF and CoordToMilsF exist before use. DelphiScript has no forward declarations, so this matters.
  • Callers expecting integers. The only int() casts near PCB coordinates on the Python side are in component placement, which this does not touch. Nothing parses the changed getters as int.

Two follow-ups on our side, neither of them yours to fix:

  • SCRIPT_VERSION needed bumping, since Python compares it against what Altium has loaded and refuses to run mismatched. Done in 7d207af, now 2026.09.19.5.
  • tests/altium_simulator.py still does int(float(params["x"])), so simulator-backed tests quantise to 1 mil and will not exercise sub-mil. Worth fixing before the next change in this area, or the coverage is theatre.

One question: the four { sub-mil coordinates: local patch 2026-09-18 } comments are still in the code. They read as markers from your local workflow. I left them rather than edit your commit. Say the word and I will strip them, or leave them if they are useful to you.

Cherry-picked rather than merged through the PR, so this shows as closed rather than merged. Both commits carry your authorship.

@salitronic salitronic closed this Sep 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants