Skip to content

Latest commit

 

History

1 Commit

Folders and files

Repository files navigation

shapefit-lite

Tell whether a hand-drawn stroke is a straight line or a circle, with a fit score.

Synthetic strokes (gray) with the fitted line (blue) or circle (red)

Quick start

git clone https://github.com/207studio/shapefit-lite && cd shapefit-lite
cargo test && cargo run --example demo
swift test   # needs Xcode or a Swift 5.9 toolchain

Rust:

use shapefit_lite::{classify, Fit, Options, Point};

let stroke = [Point::new(0.0, 0.0), Point::new(50.0, 1.0), Point::new(100.0, 0.0)];
if let Fit::Line { start, end, score } = classify(&stroke, &Options::default()) {
    println!("line from {start:?} to {end:?}, score {score:.2}");
}

Swift:

import ShapeFitLite

let fit = classify([Point(x: 0, y: 0), Point(x: 50, y: 1), Point(x: 100, y: 0)])

The line fit is total least squares. The circle fit is a Kåsa fit refined by a few Gauss-Newton steps. Residuals are scale-free: the line residual is divided by the stroke's bounding-box diagonal and the circle residual by the radius. A circle also needs the stroke to cover at least 70% of it. score is 1 - residual / max_residual, clamped to 0..1. The defaults are max_residual = 0.1 and min_circle_coverage = 0.7.

Rust and Swift share fixtures/strokes.json (regenerate with cargo run --example make_fixtures). Both test suites check their output against it within 1e-6 relative.

Full version

ShapeFit snaps a paused stroke to a clean line, circle, ellipse, rectangle, triangle or polygon, with hold-to-shape timing and angle snapping, and Rust and Swift give identical output on a 600-stroke check. No ML, zero dependencies.

ShapeFit on 207studio.dev

How it compares

  • This teaser knows two shapes: line and circle. The full version also fits ellipses, rectangles, triangles and polygons.
  • This teaser only classifies a finished stroke. The full version adds hold-to-shape timing and angle snapping.
  • This teaser checks Rust and Swift against 10 shared strokes. The full version checks them against 600.
  • Both have zero dependencies and use no ML.

What it does NOT do

It does not detect a pause or hold at the end of a stroke. It does not fit ellipses, rectangles, triangles or polygons. It does not snap lines to 45-degree angles. It does not detect corners. It has no PencilKit integration and no live drawing UI. It does not smooth or resample strokes beyond what the fit needs. It is not a replacement for ShapeFit.

License

MIT. See LICENSE.

Releases

Packages

Contributors

Languages