pub struct StrokeModeler { /* private fields */ }
Expand description
This class models a stroke from a raw input stream. The modeling is performed in several stages
- Wobble smoothing : dampens high-frequency noise from quantization error
- Position modeling : models the pen tip as a mass, connected by a spring, to a moving anchor
- Stylus state modeling : constructs stylus states for modeled positions by interpolating over the raw input
Additional, this class provides prediction of the modeled stroke
StrokeModeler is unit-agnostic
Implementations§
source§impl StrokeModeler
impl StrokeModeler
Notations
We denote :
-
Pressure :
-
time :
-
point : defined by position and (or )
-
Raw inputs are denoted by a tuple with .
An input stream is a sequence of raw inputs
-
with time strictly increasing
-
starts with a
Down
event -
contains
Move
for -
ends either with a
Move
or aUp
. If it is aUp
we say the input stream is complete
We addition define
-
as the velocity and acceleration.
With the vector shorthand and
Resampling
Algorithm : Upsampling
Input :
and a target rate sampling_min_output_rate
, Interpolate
time and position between each
by linearly adding interpolated values
This is done by adding linearly interpolated values so that the output
stream is
Each
is the minimum integer such that
and the linear
interpolation means
Output :
the upsampled position and times. This verifies
Remark : As this is a streaming algorithm, we only
calculate this interpolation with respect to the latest stroke
position.
Position modeling
The raw input is processed as follow
raw input wobble smoother upsampled position modeling
The position of the pen is modeled as a weight connected by a spring to an anchor.
The anchor moves along the resampled dewobbled inputs, pulling the weight along with it across a surface, with some amount of friction. Euler integration is used to solve for the position of the pen.
The physical model that is used to model the stroke is the following where
-
is time
-
is the position of the pen
-
is the position of the anchor
-
and are constants that sets how the spring and drag occurs
is given by position_modeler_spring_mass_constant
and
by position_modeler_drag_constant
We will thus have as input the upsampled dewobbled inputs taking the role of discretized and will be the output
Modeling a stroke.
-
Input : input stream
-
Output : smoothed stream
We define . An euler scheme integration scheme is used with the initial conditions being and (same initial conditions)
Update rule is simply The position is the main thing to export but we can also export speed and acceleration if needed. We denote and this will be our output with
Stylus state modeler
Up till now we have only used the raw input stream to create a new
smoothed stream of positions, leaving behind the pressure attribute.
This is what’s done here, to model the state of the stylus for these new
position based on the pressure data of the raw input strokes.
Algorithm Stylus state modeler
Input :
-
input stream with pressure information
-
query position
-
search window (From
stylus_state_modeler_max_input_samples
),
initialize
,
,
for
to
do
- Find
the position that’s closest to
on the segment
and denote
the value such that
- if
-
- endif
endfor
calculate
Output : interpolated pressure
Stroke end
The position modeling algorithm will lag behind the raw input by some
distance. This algorithm iterates the previous dynamical system a few
additional time using the raw input position as the anchor to allow a
catch up
of the stroke (though this prediction is only
given by predict
, so is not part of the
results
and becomes obsolete on the next input).
Algorithm :Stroke end
Input:
-
Final anchor position (From the original input stream)
-
final tip state (returned from the physical modeling from the last section, signifies that we are looking at the filtered output)
-
max number of iterations (
sampling_end_of_stroke_max_iterations
) -
the target time delay between stroke (1/
sampling_min_output_rate
) -
stopping distance (
sampling_end_of_stroke_stopping_distance
) -
and the modeling coefficients
initialize the vector
with
initialize
for
- calculate the next candidate
- if
(further iterations won’t be able to catch up and won’t move closer to
the anchor, we stop here), - return
- endif
-
if (we’ve overshot the anchor, we retry with a smaller step)
-
,
-
continue (this candidate will be discarded, try again with a smaller time step instead),
-
- else
-
(We append the result to the end of the
vector)
- endif
-
if ,
-
return (We are within tolerance of the anchor, we stop iterating),
-
-
endif,
Output :
pub fn new(params: ModelerParams) -> Result<Self, String>
sourcepub fn reset_w_params(&mut self, params: ModelerParams) -> Result<(), String>
pub fn reset_w_params(&mut self, params: ModelerParams) -> Result<(), String>
Clears any in-progress stroke, and re initialize the model with the given parameters
sourcepub fn update(
&mut self,
input: ModelerInput,
) -> Result<Vec<ModelerResult>, ModelerError>
pub fn update( &mut self, input: ModelerInput, ) -> Result<Vec<ModelerResult>, ModelerError>
Updates the model with a raw input, and appends newly generated Results to the results vector. Any previously generated Result values remain valid. (This does not require that any previous results returned remain in the results vector, as it is appended to without examining the existing contents)
If this does not return an error, results will contain at least one Result, and potentially more if the inputs are slower than the minimum output rate