//! Recognition of handwritten math (Issue #46, stage 2). //! //! Turns the strokes of a handwritten expression into text for [`crate::math::solve`], e.g. //! the strokes of `(x+3)²=` into `(x+3)^(2)=`. It works on the stroke points, not on an //! image, in three steps: //! //! 1. **Grouping**: consecutive strokes that overlap form one symbol (the two strokes of `+`, //! `x` or `4`). Straight horizontal strokes and dots are kept apart, as their meaning //! depends on their neighbours. //! 2. **Classifying** each symbol with the $P point-cloud recognizer (Vatavu, Anthony, //! Wobbrock 2012): its points are compared with templates of each symbol. It does not //! depend on stroke order or direction and needs no trained model; besides the built-in //! templates, one's own handwriting can be added as templates. //! 3. **Structure** from the positions: two stacked lines are `=`, two stacked dots `:`, a //! line with symbols above and below is a fraction bar, a dot low between digits a //! decimal comma, and smaller raised symbols an exponent. use glam::{Vec2, Vec3}; /// Points of a symbol after resampling, for $P const CLOUD_POINTS: usize = 32; /// Symbols whose best template is further away are not recognized ($P distance) const MAX_DISTANCE: f32 = 3.0; /// Factor on the distance per stroke more or less than the template has const STROKE_PENALTY: f32 = 0.15; /// Slants of the built-in templates (horizontal shift of the top against the bottom) const TEMPLATE_SLANTS: [f32; 2] = [0.0, 0.25]; /// Weight of the turning angle against the position of a point ($P+) const ANGLE_WEIGHT: f32 = 1.0; /// A recognized symbol with the area it covers and the strokes it consists of #[derive(Debug, Clone, PartialEq)] pub struct Symbol { /// `0`–`9`, `x`, `y`, `a`, `b`, `+`, `-`, `·`, `:`, `/`, `(`, `)`, `=`, `,` or `?` pub ch: char, pub min: Vec2, pub max: Vec2, /// Indices into the strokes passed to [`Recognizer::recognize`] pub strokes: Vec, } /// Result of [`Recognizer::recognize`] #[derive(Debug, Clone, PartialEq)] pub struct Recognition { /// The expression as text, e.g. `(x+3)^(2)=` or `((1)/(2))+3=` pub text: String, /// All symbols, from left to right pub symbols: Vec, } struct Template { symbol: char, strokes: usize, cloud: Vec, } /// $P recognizer with templates for the symbols of simple math pub struct Recognizer { templates: Vec