#!/usr/bin/env python3 """v6 T3c - replace scientific-notation COORDINATES with exact 0. Float accumulation in the T3a/T3b generators emitted coordinates like 3.552713679e-15 (i.e. zero). KiCad's s-expression parser is not guaranteed to accept exponent notation. !! LESSON (2026-08-24): a first attempt used a bare numeric regex over the whole file and corrupted 264 UUIDs - segments such as "895e-4153" parse as scientific notation. This version ONLY touches tokens inside an (at ...) form, only when the token is a complete float in exponent form, and only when |value| < 1e-9. It also refuses to run if any UUID would change. Usage: python3 2026-08-24_v6_T3c_fix_sci_notation.py [--apply] """ import re, sys, os, shutil KI = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '03-Architecture-Hardware', 'kicad') FILES = [os.path.join(KI, 'Drogheda-sym.kicad_sym'), os.path.join(KI, 'hbox-watchdog-v6.kicad_sch')] APPLY = '--apply' in sys.argv AT = re.compile(r'\(at ([^()]*)\)') NUM = re.compile(r'^[+-]?(?:\d+\.?\d*|\.\d+)[eE][+-]?\d+$') UUID = re.compile(r'\(uuid "([^"]*)"\)') total = 0 for f in FILES: src = open(f, encoding='utf-8').read() changed = [] def fix(m): toks = m.group(1).split() out = [] for t in toks: if NUM.fullmatch(t): v = float(t) if abs(v) >= 1e-9: sys.exit('REFUSING: non-negligible exponent coordinate %s' % t) changed.append((m.group(0), t)); out.append('0') else: out.append(t) return '(at ' + ' '.join(out) + ')' new = AT.sub(fix, src) if UUID.findall(new) != UUID.findall(src): sys.exit('REFUSING: a UUID would change - aborting') print('%-30s %d coordinate(s) fixed' % (os.path.basename(f), len(changed))) for before, tok in changed: print(' %s (token %s -> 0)' % (before, tok)) total += len(changed) if APPLY and changed: shutil.copy2(f, f + '.T3cbak'); open(f, 'w', encoding='utf-8').write(new) print('total: %d' % total) print('APPLIED' if APPLY else '\nDRY RUN - nothing written. Re-run with --apply.')