7.5 KiB
E440 arc-dial scale generator — design
Summary
Pivot the repository from generating M1730 linear-strip meter scales to
generating E440-style round-dial meter scales, matching the hand-drawn
reference e440.svg. This is a full replacement, not an added mode: the
M1730 linear generator, its three SVG files, and its infra naming are all
retired and replaced by E440 equivalents. Feature parity is kept wherever it
translates naturally (scale mappings, output modes, custom labels, unit
markup) but re-expressed in polar terms (angle/radius) instead of Cartesian
(x-position).
Case geometry (fixed constants)
The physical dial body, exactly as drawn in e440.svg, does not change
between generated scales — only the tick/label/text content does. This
mirrors how M1730's background panel rectangle was a fixed constant.
- Canvas: 93.824249 × 57.215687 mm,
layer1transformtranslate(-60.717741,-107.14126)(same convention as M1730: constants are expressed in this pre-translate local frame). - Body outline + two mounting ears + rim cutout: the existing
<path id="path2">ine440.svg, carried over unchanged. - Pivot center: local
(107.42845, 162.62819). Small gray guide circle (r≈1.73mm) at the pivot is kept as-is. - Rim / tick-base radius
R0 = 43.842751mm — ticks start here and extend outward. - Angular sweep:
[-45.667°, +45.667°]measured from vertical (north), negative = left/low end, positive = right/high end, clockwise-positive (matches the reference: 0 at the left end, 50 at the right end).
Tick generation (parametrized, 3 tiers)
Same conceptual parameters as the M1730 generator (big_ticks,
small_ticks, label_count), reinterpreted along the arc:
- Major ticks — one per major interval boundary (
big_ticks + 1of them), evenly spaced in angle across the sweep. Radial length 4.7839mm, stroke-width 0.7966. These are the ones eligible for numeric labels. - Medium tick — appears only when
small_ticksis odd, at the exact midpoint subdivision of each major interval (e.g.small_ticks=9→ 10 subdivisions → the 5th is the midpoint). Radial length 3.1216mm, stroke-width 0.3799. This matches the reference exactly (values 5, 15, 25, 35, 45 get a medium tick between the 0/10/20/30/40/50 majors). - Small ticks — every other subdivision. Radial length 1.8122mm, stroke-width 0.2748.
- If
small_ticksis even, there's no exact midpoint — all minor subdivisions render as small ticks (2-tier fallback), no medium tier.
Each tick is emitted as a <line> from (R0, angle) to (R0+length, angle) in polar coordinates around the pivot (as <line> elements, not
rotated <rect>s like the hand-drawn file — simpler and consistent with how
M1730's code already draws ticks as lines rather than filled rotated boxes).
Minor-tick angular placement under each scale mapping (linear/√/log/1/x) carries over directly from the M1730 code, substituting angle for x.
Labels
Numeric labels are positioned at radius ≈49.86mm (just beyond the major tick
tips) and rotated to match their tick's angle — following the arc, as in
the reference (confirmed: "rotated/radial" was the chosen orientation).
Default label font size ≈5.11mm (kept configurable, like label_size
today). Label placement/count logic (label_count, custom_labels,
_fmt()) is an unchanged port from the M1730 code.
Unit label and corner text
- Unit label (e.g.
uA): centered above the arc at local(107.035, 136.646), horizontal (not rotated), default size ≈9.47mm. Markup support (^,_,{a/b}) is preserved — same parser as today. - Corner labels replace M1730's single
range_label/ colored bar (which E440 doesn't have): two independent fields, left and right, each up to 2 lines, anchored at the reference'stext58/text61positions (bottom-left start-anchored, bottom-right end-anchored, ≈3.57mm font size, ≈4.46mm line spacing). A field's second line is only drawn if provided; no truncation beyond 2 lines (extra input past line 2 is ignored).
Fonts
Single font selector, unchanged mechanism from today (any .ttf dropped in
fonts/ is auto-discovered and offered in the dropdown). Default font
becomes alte-din-1451-mittelschrift.regular (already present in
fonts/). The .gepraegt (embossed) variant and the existing GOST-family
fonts remain selectable but are not auto-paired to any specific element —
whatever the user picks in the dropdown is used for unit, labels, and corner
text alike, exactly like the current single-selector behavior.
Scale mappings, output modes, custom labels
All four mappings (linear, √, log, 1/x) are kept, each reusing its existing
value_to_x/major_value math from web/app.py, renamed conceptually to
value_to_angle. Dual output mode (path-outlines vs. embedded live text)
and custom label override are both kept unchanged in behavior, just applied
to the new geometry.
File deliverables
e440.svg→ renamed/tidied intoE440-Scale_template.svg(updatesodipodi:docname, keep as the Inkscape master with the same reference values: unituA, range 0–50,Text/LeftandText/Rightcorner placeholders).E440-Scale_paths.svg— same content with all text converted to outline<path>s via fontTools (mirrors howM1730-Scale_paths.svgwas derived).E440-Scale_text.svg— same content with the font embedded as base64@font-face,sodipodi:docnameset toE440-Scale.svg(the "final named file", matching the old convention).- Old
M1730-Scale_template.svg,M1730-Scale_paths.svg,M1730-Scale_text.svgare deleted.
web/app.py changes
generate_svg(...)rewritten around polar geometry: new constants (PIVOT_X,PIVOT_Y,R0,ANGLE_MIN,ANGLE_MAX, tick lengths/widths per tier, label radius) replace the linearZERO_X/MAX_X/BAR_Y/tick height constants.range_labelparameter replaced byleft_label/right_label(each a string,\n-split into up to 2 lines).- Body/case SVG markup (the fixed
<path>for the dial body + pivot guide circle) is emitted as a fixed literal, same pattern as today's fixed background<path>. - Existing helper functions (
_glyph_svg,_measure,_parse_markup,_text_to_paths,_fmt, the fraction/sup/sub renderer) are reused unchanged — they're geometry-agnostic. - Form (
web/templates/index.html) fields updated: drop "Range label", add "Left label" / "Right label" (2-line text areas), everything else (unit, min/max, mapping, major/minor tick counts, label count/size, custom labels, font, output mode) stays.
Rebranding
Full rename to E440 branding across infra and docs:
- Docker image tag
m1730-scale→e440-scale. k8s/ingress.yamlrouteworks.baumann.gr/M1730-generator→works.baumann.gr/E440-generator(and its stripPrefix middleware).README.mdandCLAUDE.mdrewritten to describe the E440 arc-dial project: new file roles, new coordinate constants, new tick-tier rules, new default font, new form fields.
Testing / verification
No automated test suite exists in this repo (consistent with "no build,
lint, or test tooling" in CLAUDE.md). Verification is: run the Flask app
locally, generate a scale reproducing the exact reference parameters
(unit uA, 0–50, 5 major intervals, 9 minor per interval, labels every
major, corner texts Text/Left and Text/Right), and visually diff the
output against E440-Scale_template.svg (tick angles/positions, label
placement, corner text placement) to confirm the geometry model is correct
before considering the port done.