6 Commits

Author SHA1 Message Date
Samuel Prevost
da5be3851d feat: world-axis selector, 8-point circle, annotated measurement tool
Datum editor (step 3):
- Add world-axis role to rectangles (isAxisReference) and lines
  (axisRole: "x"|"y"). Exclusive via a new store action that clears
  any other axis flag on write. The solver's pickPrimary now honors an
  explicit user flag ahead of the type-priority fallback; line-primary
  correspondences target world +x or +y depending on the flag.
- Panel UI: checkbox on rect cards, three-way button row on line cards,
  and an axis badge in each card header.
- Ellipse datum switches to 8 user-placed points on the circle contour.
  New src/lib/ellipse-fit.ts does an algebraic LSQ conic fit (data-
  normalised, 5x5 Gaussian solve, f=-1 constraint) and returns the
  geometric center + perpendicular conjugate semi-axes, which we cache
  on the datum for the solver and renderer. Dragging any handle
  refits; an extra center handle translates all 8 points together.
  datum-cache migrates legacy 3-handle storage by synthesising 8
  samples from the old parametric form.
- ResultViewer auto-scale now floors to an int to match the integer-
  only scale input (step=1).

Measurement tool (step 4) — CorrectedImageViewer.vue:
- Three measurement tools: line (length), ellipse (semi-axes + area),
  angle (0-180 degrees between two rays).
- Persistent, multi-measurement state. Each has id, colorIndex, and
  type-specific geometry; colors cycle via the existing getDatumColor
  palette with a monotonic counter so deletion doesn't recolor.
- Selection model with hit-testing on handles, geometry, and labels.
  Selected draws on top in white; others render dashed with 0.8/0.5
  alpha so the active measurement pops.
- Dragging geometry or label moves the whole measurement; dragging a
  handle reshapes just that handle. 3px mouse threshold distinguishes
  click from drag.
- Side panel lists measurements with color chip, type, value, and a
  delete button; clicking selects on canvas. Delete/Backspace deletes
  the selected measurement. Escape cancels in-progress placement.
- Live placement preview + inline hint strip describes what the next
  click does. Pinch-zoom and single-finger pan still work.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 18:10:22 +02:00
Samuel Prevost
b87f933b9e feat(solver): iterative homography solver with circle datums
Replace the two-pass closed-form deskew (getPerspectiveTransform +
per-axis scale corrections) with an alternating-minimisation loop around
cv.findHomography (internal Levenberg–Marquardt). Each outer iteration
recomputes per-datum point correspondences from the current H and the
datum's shape constraint, then findHomography refines H. Confidence
drives per-correspondence replication; primary gets a 3× gauge boost.

- Add EllipseDatum type (center + two conjugate semi-axis endpoints +
  known diameter) with 3-handle Konva rendering and coin presets.
- Generalise primary selection to any datum type. Priority rect >
  ellipse > line; within type, confidence then image size. Warm-start
  anchors: rect = 4 axis-aligned corners; ellipse = 4 conjugate-axis
  samples on a world circle; line = 2 endpoints + 2 synthetic
  perpendicular points (isotropic image-scale assumption).
- Direction-agnostic shape residuals: Procrustes-fit ideal (w × h) rect
  to projected corners; midpoint-preserving line rescale; radial-snap
  ellipse samples to a circle at projectPoint(H, center).
- Drop the "at least one rectangle" requirement. Any datum combination
  works; diagnostics widgets auto-pick a scale reference across types.
- Diagnostics: replace X/Y axis-correction cards with RMS residual +
  iteration count; per-datum table shows a residual breakdown column
  (edge %, perp Δ°, iso/skew/dia).
- Detect period-2 oscillation in the outer loop and warn to console.
- Relative convergence threshold so the affine and perspective entries
  of H are weighted comparably.
- Guard diagnostic diameter via geometric-mean-radius for non-circular
  conics; guard collinear-axes ellipses; fix Mat leak in
  solveHomography on the exception path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 17:42:40 +02:00
Samuel Prevost
e72c4bc89b fix(canvas): fix mobile touch interactions and desktop panning
Some checks failed
Deploy to GitHub Pages / build (push) Has been cancelled
Deploy to GitHub Pages / deploy (push) Has been cancelled
- Mobile: fix pinch-zoom jitter by disabling Konva stage drag during
  two-finger gestures so only our zoom handler controls position
- Mobile: fix dot dragging — defer pan start so Konva can claim touch
  for shape drag first (isDraggingShape flag)
- Desktop: enable stage drag for click-drag panning, disable during
  point drag; filter dragend by nodeType to prevent offset corruption
- Fallback file hash using name+size+lastModified when crypto.subtle
  is unavailable (HTTP contexts, some mobile browsers)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-04-14 23:51:29 +02:00
Samuel Prevost
98c6fc9a35 feat(ui): squirrel logo, fork ribbon, clickable steps, and polish
- Squirrel engineer logo (SkwikLogo.vue) with hard hat and ruler
- Matching favicon with squirrel head silhouette
- Gitea fork ribbon (top-left, desktop only, Gitea green)
- Centered header with logo, title, and subtitle
- Footer: "Made by Samuel Prevost" with GitHub link
- Clickable step indicators for previously visited steps
- Smaller datum dots (6/4 base radius with visual cap)
- Engineering-tool styling: monospace for measurements, Geist Mono
  font, deeper dark mode colors, instrument-panel header
- EXIF viewer explains why focal length matters
- Upload page describes what Skwik does

Co-Authored-By: Claude <noreply@anthropic.com>
2026-04-14 23:19:44 +02:00
Samuel Prevost
4069491c2f Implement real deskew algorithm and UI improvements
- Replace placeholder with OpenCV.js WASM perspective correction:
  pick highest-confidence rectangle, compute homography, fold
  weighted scale corrections from secondary datums, single warpPerspective
- All units now mm throughout (no cm conversion)
- Simplified datum creation: two buttons (+ Rectangle / + Line) with
  preset chips, auto-numbered labels (Line 1, Rectangle 2, etc.)
- Dimensions default to 0, user must input manually; Next button
  disabled until all datums have valid dimensions with tooltip hint
- Fix image preview (keep object URL alive), fix canvas disappearing
  on breakpoint switch (single instance + ResizeObserver re-fit)
- Mobile responsive: bottom sheet for datum panel, full-width canvas
- Spinner on result screen during processing
- Stricter ESLint config, updated Prettier to 4-space/no-semicolons

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 21:15:53 +02:00
Samuel Prevost
2d56c5dada Initial commit: Skwik image deskew tool
Vue 3 + Vite + TypeScript (strict) app with shadcn-vue, Konva.js canvas,
and Pinia. 4-step wizard: upload JPG/HEIC, view EXIF, place datum
measurements (rectangles/lines with presets), run deskew (placeholder).
Dark mode, mobile-responsive with bottom sheet for datum panel.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 20:53:00 +02:00