Add design spec for E440 arc-dial scale generator pivot
This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
# 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, `layer1` transform
|
||||
`translate(-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">`
|
||||
in `e440.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.842751` mm — 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 + 1` of
|
||||
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_ticks` is 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_ticks` is 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's `text58`/`text61`
|
||||
positions (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 into `E440-Scale_template.svg` (update
|
||||
`sodipodi:docname`, keep as the Inkscape master with the same reference
|
||||
values: unit `uA`, range 0–50, `Text`/`Left` and `Text`/`Right` corner
|
||||
placeholders).
|
||||
- `E440-Scale_paths.svg` — same content with all text converted to outline
|
||||
`<path>`s via fontTools (mirrors how `M1730-Scale_paths.svg` was derived).
|
||||
- `E440-Scale_text.svg` — same content with the font embedded as base64
|
||||
`@font-face`, `sodipodi:docname` set to `E440-Scale.svg` (the "final
|
||||
named file", matching the old convention).
|
||||
- Old `M1730-Scale_template.svg`, `M1730-Scale_paths.svg`,
|
||||
`M1730-Scale_text.svg` are 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 linear `ZERO_X`/`MAX_X`/`BAR_Y`/tick
|
||||
height constants.
|
||||
- `range_label` parameter replaced by `left_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.yaml` route `works.baumann.gr/M1730-generator` →
|
||||
`works.baumann.gr/E440-generator` (and its stripPrefix middleware).
|
||||
- `README.md` and `CLAUDE.md` rewritten 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.
|
||||
Reference in New Issue
Block a user