3b1e244d55
- Unit label was vertical-centered on a box derived from a baseline coordinate, shifting it 3.34mm too low and making the generated deliverables inconsistent with E440-Scale_template.svg. UNIT_Y is now used directly as the baseline; regenerated E440-Scale_paths.svg and E440-Scale_text.svg accordingly. - sqrt scale's minor-tick angle formula double-applied the square-root mapping, badly misplacing minor ticks. Removed the special case so sqrt falls through to the already-correct generic value-interpolation branch. Corrected README's sqrt row (crowds toward the high end, not low). - Removed dead code: unused _has_markup(), identity-transform wrapper and _UNIT_SCALE_X in _markup_unit_svg, unreachable max_val<=0 check, redundant math.isinf() in the minor-tick condition. - Linear scale with min==max now raises ValueError like the other three mappings, instead of silently producing a degenerate dial. - Form numeric parsing moved inside the try/except so bad input returns 400 instead of crashing with 500. - left_label/right_label now split on splitlines() to handle CRLF from browser textareas correctly. - Formatting consistency: PIVOT_CIRCLE_R/R0 use :.5f like other constants; font_face indentation matches its sibling elements. - LICENSE and CLAUDE.md: last M1730-Scale references and a doc inaccuracy about which labels are live text vs. outlined paths. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
122 lines
4.9 KiB
Markdown
122 lines
4.9 KiB
Markdown
# E440-Scale
|
||
|
||
SVG scale artwork and web generator for E440-style round-dial analog panel
|
||
meters. Scales are typeset in **Alte DIN 1451 Mittelschrift**.
|
||
|
||
## Repository layout
|
||
|
||
```
|
||
E440-Scale_template.svg Inkscape working file (case body, tick marks, labels)
|
||
E440-Scale_paths.svg Paths-only export — text converted to outlines
|
||
E440-Scale_text.svg Live-text export — embedded font, editable labels
|
||
fonts/ TTF fonts (required for Docker build)
|
||
web/ Flask web generator
|
||
k8s/ Kubernetes manifests
|
||
Dockerfile Container build
|
||
```
|
||
|
||
## SVG files
|
||
|
||
The canvas is **93.824249 × 57.215687 mm**. The coordinate origin is
|
||
offset: layer 1 carries `transform="translate(-60.717741,-107.14126)"`, so
|
||
absolute SVG coordinates begin around x=61, y=107.
|
||
|
||
The dial's case geometry — body outline, mounting ears, pivot point
|
||
(local `107.42845, 162.62819`), rim radius (`43.842751` mm), and angular
|
||
sweep (`±45.667°` from vertical) — is fixed across every generated scale.
|
||
Only the tick marks, numeric labels, unit label, and corner text vary.
|
||
|
||
| File | Purpose |
|
||
|---|---|
|
||
| `E440-Scale_template.svg` | Master Inkscape file. Edit this one. |
|
||
| `E440-Scale_paths.svg` | All text converted to outlines. Use for cutting plotters, laser engravers, or any workflow where fonts must not be embedded as live text. |
|
||
| `E440-Scale_text.svg` | Live `<text>` nodes with the font embedded as base64. Smaller file; requires an SVG viewer that supports embedded fonts. |
|
||
|
||
Open files in **Inkscape** (developed with v1.4.3). There is no build step
|
||
— edit the SVG directly or use the web generator.
|
||
|
||
## Web generator
|
||
|
||
A Flask app that generates arc-dial scale SVGs from a form. Supports two
|
||
output modes switchable in the UI:
|
||
|
||
- **Paths** — glyphs rendered as outlines via fontTools; opens cleanly in
|
||
Inkscape, Illustrator, and cutting software
|
||
- **Text** — live `<text>` elements with the selected font embedded as
|
||
base64
|
||
|
||
### Run locally
|
||
|
||
```bash
|
||
source .venv/bin/activate
|
||
cd web && python app.py # http://localhost:5000
|
||
```
|
||
|
||
Fonts are loaded at startup from the `fonts/` directory in the repo root.
|
||
|
||
### Form parameters
|
||
|
||
| Field | Description |
|
||
|---|---|
|
||
| Unit | Symbol shown centered above the arc (e.g. `uA`, `V`, `%`). Supports inline markup — see below |
|
||
| Left label / Right label | Up to 2 lines each, placed in the bottom-left/bottom-right corners of the dial |
|
||
| Mapping | **Linear**, **√** (square root), **Log**, or **1/x** (reciprocal). Major ticks are always evenly spaced angularly; the mapping controls their values and how minor ticks are placed within each interval. |
|
||
| Min / Max | Numeric range of the scale |
|
||
| Major intervals | Number of major tick intervals |
|
||
| Minor per interval | Minor ticks between each pair of major ticks. When odd, the exact midpoint subdivision is drawn as a taller "medium" tick, matching the reference dial's 3-tier tick scheme |
|
||
| Labels | Number of numeric labels; Labels − 1 should divide evenly into Major intervals |
|
||
| Custom labels | Optional comma-separated labels that override the calculated numbers |
|
||
| Label size (mm) | Font size of the numeric labels, in millimetres (default `5.1126`) |
|
||
|
||
### Scale mappings
|
||
|
||
| Mapping | Major tick values | Minor tick placement | Constraints |
|
||
|---|---|---|---|
|
||
| Linear | Evenly spaced | Uniform | None |
|
||
| √ | Quadratic (0, 1, 4, 9 … × max) — compresses low values | Crowded toward the high end of each interval | Min ≥ 0 |
|
||
| Log | Geometric (min × r⁰, r¹, r² …) — each interval spans the same ratio | Crowded toward the high end of each interval | Min and Max > 0 |
|
||
| 1/x | Harmonic (values decrease left → right, e.g. ∞, 10, 5, 2, 1) — compresses high values | Uniform (in angle space, i.e. proportional to 1/v) | Min and Max > 0; Max may be ∞ |
|
||
|
||
### Unit markup
|
||
|
||
The Unit field accepts a lightweight shorthand (no LaTeX engine — everything
|
||
is drawn as glyph paths and auto-sized to fit above the arc):
|
||
|
||
| Markup | Result |
|
||
|---|---|
|
||
| `cm^2` | superscript (`^{...}` for multiple characters) |
|
||
| `H_2O` | subscript (`_{...}` for multiple characters) |
|
||
| `{1/2}` | stacked fraction with a horizontal rule; a bare `/` stays inline |
|
||
|
||
Constructs nest: `{m/s^2}` is a fraction with a superscript in the
|
||
denominator, `x^{1/2}` a superscripted fraction.
|
||
|
||
## Container
|
||
|
||
```bash
|
||
docker build -t e440-scale:latest .
|
||
docker run -p 5000:5000 e440-scale:latest
|
||
```
|
||
|
||
Fonts are loaded from `fonts/` in the repo root; they are bundled into the
|
||
image at build time.
|
||
|
||
The production image is at `git.baumann.gr/adebaumann/e440-generator`.
|
||
|
||
## Kubernetes
|
||
|
||
Manifests in `k8s/` deploy to the `works` namespace with a Traefik v2
|
||
IngressRoute at `works.baumann.gr/E440-generator`.
|
||
|
||
```bash
|
||
# Managed by ArgoCD — push to git to deploy
|
||
git push
|
||
```
|
||
|
||
Resources: namespace, deployment (1 replica, gunicorn), ClusterIP service,
|
||
Traefik IngressRoute + stripPrefix middleware.
|
||
|
||
## License
|
||
|
||
GPL-3.0 — see [LICENSE](LICENSE).
|