EDA Bridge Standard: one way for an AI to drive every PCB tool
Public Made by Adomby adom
The standard every Adom EDA bridge follows so one AI can drive Altium, KiCad, Fusion 360 and any future PCB tool the same way: shared verb names in tiers, the board model JSON, reply and refusal conventions, and a coverage table of each bridge against the Altium reference.
altium-lane: marking font, D and B no longer read as IO and 8 (body3d) #3
altium-lane: generate_body's marking font. D read as "IO" and B as an 8 with a bar. This changes engine/src/writers/body3d.rs only.
What was wrong:
- D was drawn as a closed box with a centre bar. On a QFN that Altium 26.11 rendered from engine 0.5.0, "ADOM" read "AIOM".
- B was drawn as the 8 box with that same bar.
The fix: both letters now have a full left side and cut top and bottom right corners, and B's middle bar runs to a cut notch. D, O, 0, B and 8 are now all distinct.
Checked:
- An OCCT render (step2glb, top view) of a QFN marked "ADOM / B0D8" reads correctly.
- A new test,
d_and_b_are_not_i_o_or_8, passes, and the marking-fit test still passes: 59 unit and 5 conformance in all. - No other glyph changes, and no box or solid count changes.
The only output change is the STEP geometry of a marking that contains D or B. Please release it as a patch when convenient; I'll re-vendor it with the rest.
Diff Skip to comments
@@ -1,523 +1,542 @@⋯ 311 unchanged lines ⋯ const DBL: ((f64, f64), (f64, f64)) = (MM, BL); const DBR: ((f64, f64), (f64, f64)) = (MM, BR); const LB: ((f64, f64), (f64, f64)) = (ML, BM); const RB: ((f64, f64), (f64, f64)) = (MR, BM); const DOT: ((f64, f64), (f64, f64)) = ((0.4, 0.0), (0.6, 0.0));+ // D and B: the left side full and the right corners cut, so D does not read as I and O side by side (it was a+ // box with a centre bar: "ADOM" read "AIOM" on a QFN in Altium, 2026-10-28) and B is not an 8+ const KT: (f64, f64) = (0.75, 2.0); const KM: (f64, f64) = (0.75, 1.0); const KB: (f64, f64) = (0.75, 0.0);+ const RT: (f64, f64) = (1.0, 1.75); const RU: (f64, f64) = (1.0, 1.25); const RL: (f64, f64) = (1.0, 0.75); const RB0: (f64, f64) = (1.0, 0.25);+ const DG: &[((f64, f64), (f64, f64))] = &[F, E, (TL, KT), (KT, RT), (RT, RB0), (RB0, KB), (BL, KB)];+ const BG: &[((f64, f64), (f64, f64))] = &[F, E, (TL, KT), (KT, RT), (RT, RU), (RU, KM), (ML, KM), (KM, RL), (RL, RB0), (RB0, KB), (BL, KB)]; Some(match c.to_ascii_uppercase() { '0' => &[A, B, C, D, E, F, DTR, DBL], '1' => &[V], '2' => &[A, B, G, E, D], '3' => &[A, B, G2, C, D], '4' => &[F, G, B, C], '5' => &[A, F, G, C, D], '6' => &[A, F, E, D, C, G], '7' => &[A, B, C], '8' => &[A, B, C, D, E, F, G],- '9' => &[A, B, C, D, F, G], 'A' => &[E, F, A, B, C, G], 'B' => &[A, B, C, D, V, G2], 'C' => &[A, F, E, D], 'D' => &[A, B, C, D, V],+ '9' => &[A, B, C, D, F, G], 'A' => &[E, F, A, B, C, G], 'B' => BG, 'C' => &[A, F, E, D], 'D' => DG, 'E' => &[A, F, E, D, G1], 'F' => &[A, F, E, G1], 'G' => &[A, F, E, D, C, G2], 'H' => &[F, E, B, C, G], 'I' => &[A, V, D], 'J' => &[B, C, D, E], 'K' => &[F, E, G1, DTR, DBR], 'L' => &[F, E, D], 'M' => &[E, F, B, C, DTL, DTR], 'N' => &[E, F, B, C, DTL, DBR], 'O' => &[A, B, C, D, E, F], 'P' => &[A, B, F, E, G], 'Q' => &[A, B, C, D, E, F, DBR], 'R' => &[A, B, F, E, G, DBR],⋯ 198 unchanged lines ⋯ // pins is the total in a BGA too: 64 balls are an 8 x 8 grid assert_eq!(package("bga", json!({"pins": 64}).as_object().unwrap()).unwrap().len(), 65); }++ #[test]+ fn d_and_b_are_not_i_o_or_8() {+ // D was a box with a centre bar and read as "IO"; B was an 8 with a bar+ assert_ne!(glyph('D'), glyph('O'));+ assert_ne!(glyph('B'), glyph('8'));+ for c in ['D', 'B'] {+ let g = glyph(c).unwrap();+ assert!(g.iter().all(|s| s.0 .0 != 0.5 || s.1 .0 != 0.5), "{c} has no centre bar");+ assert!(!g.iter().any(|s| (s.0 == (1.0, 2.0)) || (s.1 == (1.0, 2.0))), "{c}'s top-right corner is cut");+ }+ } }+
Reviews
Comments
Log in to comment.
No comments yet.