diff --git a/CLAUDE.md b/CLAUDE.md index ab00805..c96af76 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -14,7 +14,7 @@ The three SVG files represent layers of the same design, intended to be combined - **`E440-Scale_template.svg`** — Inkscape working template. Contains the case body path (with mounting ears and rim cutout), the pivot guide circle, tick marks, numeric labels `0`–`50`, the `uA` unit label, and `Text`/`Left` and `Text`/`Right` corner label placeholders. - **`E440-Scale_paths.svg`** — Paths-only version: all tick marks and text as ``/`` elements, no live text. Used for cutting/printing workflows where fonts must not be embedded as live text. -- **`E440-Scale_text.svg`** — Text-overlay version: tick mark lines plus live `` elements for numeric/unit/corner labels, font embedded as base64. +- **`E440-Scale_text.svg`** — Text-overlay version: tick mark lines plus live `` elements for numeric/corner labels (the unit label is always emitted as outline paths since it supports markup), font embedded as base64. ## Key Design Parameters diff --git a/E440-Scale_paths.svg b/E440-Scale_paths.svg index 4b05ff1..89b035e 100644 --- a/E440-Scale_paths.svg +++ b/E440-Scale_paths.svg @@ -2,8 +2,8 @@ - - + + @@ -66,10 +66,8 @@ - - - - + + diff --git a/E440-Scale_text.svg b/E440-Scale_text.svg index 577244d..e7647f8 100644 --- a/E440-Scale_text.svg +++ b/E440-Scale_text.svg @@ -1,10 +1,10 @@ - + - - + + @@ -62,10 +62,8 @@ 30 40 50 - - - - + + Text Left Text diff --git a/LICENSE b/LICENSE index 387efe8..b133688 100644 --- a/LICENSE +++ b/LICENSE @@ -208,7 +208,7 @@ If you develop a new program, and you want it to be of the greatest possible use To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the “copyright” line and a pointer to where the full notice is found. - M1730-Scale + E440-Scale Copyright (C) 2026 adebaumann This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. @@ -221,7 +221,7 @@ Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: - M1730-Scale Copyright (C) 2026 adebaumann + E440-Scale Copyright (C) 2026 adebaumann This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. diff --git a/README.md b/README.md index 8a3c05d..250b063 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ Fonts are loaded at startup from the `fonts/` directory in the repo root. | 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 low end of each interval | Min ≥ 0 | +| √ | 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 ∞ | diff --git a/web/app.py b/web/app.py index b60a95d..676860d 100644 --- a/web/app.py +++ b/web/app.py @@ -99,7 +99,6 @@ _FRAC_SIDE = 0.12 _UNIT_BOX_X0, _UNIT_BOX_X1 = UNIT_X - 15.0, UNIT_X + 15.0 _UNIT_BOX_Y0, _UNIT_BOX_Y1 = UNIT_Y - 6.0, UNIT_Y + 6.0 _UNIT_MAX_FS = 9.46938021 -_UNIT_SCALE_X = 1.0 def _point_at(radius: float, angle_deg: float): @@ -271,30 +270,23 @@ def _draw_nodes(nodes, x: float, y: float, fs: float, fill: str, fd: _FontData): return parts, cx - x -def _has_markup(s: str) -> bool: - return any(c in s for c in '^_') or ('{' in s and '}' in s) - - def _markup_unit_svg(unit: str, fd: _FontData, fill='#1a1a1a') -> str: nodes = _parse_markup(unit) x0, x1 = _UNIT_BOX_X0, _UNIT_BOX_X1 y0, y1 = _UNIT_BOX_Y0, _UNIT_BOX_Y1 - xc, yc = (x0 + x1) / 2, (y0 + y1) / 2 + xc = (x0 + x1) / 2 w1 = _measure(nodes, 1.0, fd) top1, bot1 = _vbounds(nodes, 1.0, fd) fs = _UNIT_MAX_FS if w1 > 0: - fs = min(fs, (x1 - x0) / (w1 * _UNIT_SCALE_X)) + fs = min(fs, (x1 - x0) / w1) if bot1 - top1 > 0: fs = min(fs, (y1 - y0) / (bot1 - top1)) w = _measure(nodes, fs, fd) - top, bot = _vbounds(nodes, fs, fd) - y_base = yc - (top + bot) / 2 - parts, _ = _draw_nodes(nodes, xc - w / 2, y_base, fs, fill, fd) - cond = f'translate({xc:.5f},0) scale({_UNIT_SCALE_X},1) translate({-xc:.5f},0)' - return f'\n{chr(10).join(parts)}\n' + parts, _ = _draw_nodes(nodes, xc - w / 2, UNIT_Y, fs, fill, fd) + return '\n'.join(parts) def _text_to_paths(text, x, y, font_size, fd: _FontData, anchor='start', fill='#1a1a1a', wrap_transform=None): @@ -387,8 +379,6 @@ def generate_svg(unit, min_val, max_val, left_label, right_label, big_ticks, sma return math.inf return min_val * big_ticks / i else: - if max_val <= 0: - raise ValueError("Reciprocal scale requires min and max values greater than 0.") k = 1.0 / min_val - 1.0 / max_val def value_to_angle(v): @@ -399,10 +389,10 @@ def generate_svg(unit, min_val, max_val, left_label, right_label, big_ticks, sma else: span = max_val - min_val + if span == 0: + raise ValueError("Linear scale requires min and max values to differ.") def value_to_angle(v): - if span == 0: - return ANGLE_MIN return ANGLE_MIN + (ANGLE_MAX - ANGLE_MIN) * (v - min_val) / span def major_value(i): @@ -434,7 +424,7 @@ def generate_svg(unit, min_val, max_val, left_label, right_label, big_ticks, sma ) font_face = ( - '