Appearance
Spec: Dual-Unit Grid System (Metric/Imperial)
Overview
Refactor the coordinate and grid system to support both metric (mm) and imperial (mil/inch) units with proper grid presets for schematic capture and future PCB layout. Introduce type-safe coordinate handling, a unified snap engine, and standard EDA grid series.
Motivation
DigitalWorks is evolving from a digital logic simulator into a full schematic editor and eventually a PCB design tool. Professional EDA tools (KiCad, Altium, DipTrace, Eagle) all support dual-unit systems because:
- Schematic symbols use mil-based grids (50 mil pin pitch is universal)
- PCB components mix imperial (through-hole on 100 mil) and metric (fine-pitch SMD on 0.5mm/0.4mm)
- Users expect to toggle between mm and mil display freely
- File interchange requires unambiguous unit metadata
The current system stores coordinates in mils with PixelsPerMil = 1.0, which is correct for schematics but needs formalization for PCB support.
Current State
- Internal unit: mils (implicitly, via
MeasurementSystem.cswithPixelsPerMil = 1.0) - Grid: Single
GridSizeInUnits(default 50 mil) inGridSettings - Snap: Duplicated in
GridSettings.SnapToGrid()andCircuitEditorAdapter.Snap() - Persistence: Raw doubles in
.dwcircuitJSON, no unit metadata - Shape definitions: Coordinates in component-local mils (10, 20, 40, 60 etc.)
- Display: No user-visible unit indicator or switching
Requirements
Functional Requirements
FR-1: Unit System
- Support three display units: Millimeter (mm), Mil (thou), Inch
- Internal storage remains mil-based (1 mil = 0.0254 mm) for backward compatibility
- All coordinate display, input fields, and rulers show values in the selected display unit
- Unit switching is instant (no data conversion — only display changes)
FR-2: Grid Presets
- Schematic grid presets (mil-based, standard EDA series):
- 50, 25, 10, 5 mil
- PCB Imperial grid presets:
- 100, 50, 25, 12.5, 6.25, 3.125, 1 mil
- PCB Metric grid presets:
- 2.54, 1.27, 0.635, 0.5, 0.25, 0.1, 0.05 mm
- Custom grid size entry (in current display unit)
- Grid presets organized by context (Schematic / PCB Imperial / PCB Metric)
FR-3: Snap Engine
- Single unified snap implementation (eliminate duplication)
- Snap-to-grid (configurable on/off, Ctrl to temporarily toggle)
- Snap-to-pin (when dragging wire endpoints near component pins)
- Snap-to-object (alignment guides to nearby component edges)
- All snap operations respect the active grid size
FR-4: Coordinate Display
- Status bar shows cursor position in current display unit
- Component property panels show position/size in current display unit
- Grid size selector shows values in current display unit
- Ruler/measurement overlays in current display unit
FR-5: File Format
.dwcircuitJSON includes"units": "mil"metadata field- Files without unit metadata assumed to be mils (backward compatible)
- Future: support saving in mm-based files for PCB context
Non-Functional Requirements
- NF-1: Unit conversion must be lossless at display precision (3 decimal places for mm, 1 for mil)
- NF-2: Snap operations must be O(1) per point (no scanning)
- NF-3: Grid rendering must not allocate per frame
- NF-4: Backward compatible — existing .dwcircuit files load without changes
Design
Internal Coordinate Unit
Keep mils as the internal unit. This matches the existing codebase, all shape definitions, and is the natural unit for schematic capture (50-mil symbol grid, 100-mil pin pitch).
For future PCB mode, mils remain appropriate — KiCad uses nanometers internally but mils are sufficient for schematic-level precision and simpler to reason about.
Grid Preset Series
The DipTrace-style mm values are simply the imperial series converted:
Imperial (mil) Metric (mm)
───────────── ───────────
1 0.0254
3.125 0.0794
6.25 0.159
12.5 0.318
25 0.635
31.25 0.794
50 1.27
100 2.54
150 3.81
200 5.08
300 7.62Additional metric-native grids for fine-pitch SMD:
- 0.5 mm (19.685 mil) — QFP/QFN pitch
- 0.4 mm (15.748 mil) — fine BGA pitch
- 0.25 mm (9.843 mil) — ultra-fine pitch
- 0.1 mm (3.937 mil) — precision routing
Architecture
┌─────────────────────────────────────┐
│ Display Layer │
│ (mm / mil / inch formatting) │
├─────────────────────────────────────┤
│ Snap Engine │
│ (grid snap, pin snap, object snap) │
├─────────────────────────────────────┤
│ GridSettings │
│ (grid size, presets, visibility) │
├─────────────────────────────────────┤
│ MeasurementSystem │
│ (unit conversions, internal→display│
│ display→internal, formatting) │
├─────────────────────────────────────┤
│ Internal Coordinates │
│ (all values stored in mils) │
└─────────────────────────────────────┘Key Classes
MeasurementSystem— static unit conversion + formatting (exists, to be extended)GridPresets— defines standard grid series for each contextSnapEngine— unified snap logic (replaces dual implementations)GridSettings— grid configuration (exists, to be extended with presets)CoordinateFormatter— formats coordinates for display in current unit
Implementation Tasks
- Extend
MeasurementSystemwith grid preset series and formatting helpers - Add
GridPresetsclass with Schematic/PCB-Imperial/PCB-Metric series - Create
SnapEnginereplacing dual snap implementations - Update
GridSettingsto use preset system and expose unit-aware grid size - Add unit metadata to
.dwcircuitfile format - Update status bar cursor display to show units
- Update Preferences grid size selector with preset dropdown
- Add unit toggle (mm/mil) to status bar or toolbar
Migration
- Existing files: no unit header → assume mils (current behavior preserved)
- Existing grid sizes: remain valid (50 mil default unchanged)
- Shape definitions: no change needed (already in mils)
- Pin positions: no change needed (already in mils)