ink_stroke_modeler_rs/
engine.rs

1use crate::error::{ElementError, ElementOrderError};
2use crate::position_modeler::PositionModeler;
3use crate::state_modeler::StateModeler;
4use crate::utils::interp;
5use crate::utils::normalize01_64;
6use crate::{ModelerError, ModelerInput, ModelerInputEventType, ModelerParams, ModelerResult};
7use std::collections::VecDeque;
8use std::vec;
9
10/// smooth out the input position from high frequency noise
11/// uses a moving average of position and interpolating between this
12/// position and the raw position based on the speed.
13/// high speeds movements won't be smoothed but low speed will.
14///
15/// wrapper time to include all needed information
16/// in the Deque
17#[derive(Debug)]
18pub(crate) struct WobbleSample {
19    /// raw position
20    pub position: (f64, f64),
21    /// position weighted by the duration
22    pub weighted_position: (f64, f64),
23    /// distance to the previous element
24    pub distance: f64,
25    /// time distance to the previous element
26    pub duration: f64,
27    /// time of the event
28    pub time: f64,
29}
30
31/// This class models a stroke from a raw input stream. The modeling is performed in
32/// several stages
33/// - Wobble smoothing : dampens high-frequency noise from quantization error
34/// - Position modeling : models the pen tip as a mass, connected by a spring, to a moving
35///   anchor
36/// - Stylus state modeling : constructs stylus states for modeled positions by interpolating
37///   over the raw input
38///
39/// Additional, this class provides prediction of the modeled stroke
40///
41/// StrokeModeler is unit-agnostic
42pub struct StrokeModeler {
43    // all configuration parameters
44    pub(crate) params: ModelerParams,
45    /// wobble smoother structures
46    /// deque to hold events that are recent
47    /// to calculate a moving average
48    pub(crate) wobble_deque: VecDeque<WobbleSample>,
49    /// running weighted sum
50    pub(crate) wobble_weighted_pos_sum: (f64, f64),
51    /// running duration sum
52    pub(crate) wobble_duration_sum: f64,
53    /// running distance sum
54    pub(crate) wobble_distance_sum: f64,
55    // physical model for the stroke
56    // only created on the first stroke
57    pub(crate) position_modeler: Option<PositionModeler>,
58    pub(crate) last_event: Option<ModelerInput>,
59    pub(crate) last_corrected_event: Option<(f64, f64)>,
60    pub(crate) state_modeler: StateModeler,
61}
62
63impl Default for StrokeModeler {
64    fn default() -> Self {
65        let params = ModelerParams::suggested();
66
67        Self {
68            params,
69            wobble_deque: VecDeque::with_capacity(
70                (2.0 * params.sampling_min_output_rate * params.wobble_smoother_timeout) as usize,
71            ),
72            wobble_weighted_pos_sum: (0.0, 0.0),
73            wobble_duration_sum: 0.0,
74            wobble_distance_sum: 0.0,
75
76            last_event: None,
77            last_corrected_event: None,
78            position_modeler: None,
79            state_modeler: StateModeler::new(params.stylus_state_modeler_max_input_samples),
80        }
81    }
82}
83
84#[doc = include_str!("../docs/notations.html")]
85#[doc = include_str!("../docs/resampling.html")]
86#[doc = include_str!("../docs/position_modeling.html")]
87#[doc = include_str!("../docs/stylus_state_modeler.html")]
88#[doc = include_str!("../docs/stroke_end.html")]
89impl StrokeModeler {
90    pub fn new(params: ModelerParams) -> Result<Self, String> {
91        params.validate()?;
92        Ok(Self {
93            params,
94            last_event: None,
95            last_corrected_event: None,
96            wobble_deque: VecDeque::with_capacity(
97                (2.0 * params.sampling_min_output_rate * params.wobble_smoother_timeout) as usize,
98            ),
99            wobble_duration_sum: 0.0,
100            wobble_weighted_pos_sum: (0.0, 0.0),
101            wobble_distance_sum: 0.0,
102            position_modeler: None,
103            state_modeler: StateModeler::new(params.stylus_state_modeler_max_input_samples),
104        })
105    }
106
107    /// Clears any in-progress stroke, keeping the same model parameters
108    pub fn reset(&mut self) {
109        self.wobble_deque.clear();
110        self.wobble_weighted_pos_sum = (0.0, 0.0);
111        self.wobble_duration_sum = 0.0;
112        self.position_modeler = None;
113        self.last_event = None;
114        self.last_corrected_event = None;
115        self.state_modeler
116            .reset(self.params.stylus_state_modeler_max_input_samples);
117    }
118
119    /// Clears any in-progress stroke, and re initialize the model with
120    /// the given parameters
121    pub fn reset_w_params(&mut self, params: ModelerParams) -> Result<(), String> {
122        params.validate()?;
123        self.params = params;
124        self.wobble_deque = VecDeque::with_capacity(
125            (2.0 * params.sampling_min_output_rate * params.wobble_smoother_timeout) as usize,
126        );
127        self.wobble_weighted_pos_sum = (0.0, 0.0);
128        self.wobble_duration_sum = 0.0;
129        self.wobble_distance_sum = 0.0;
130        self.position_modeler = None;
131        self.last_event = None;
132        self.last_corrected_event = None;
133        self.state_modeler
134            .reset(params.stylus_state_modeler_max_input_samples);
135        Ok(())
136    }
137
138    /// Updates the model with a raw input, and appends newly generated Results to the results vector.
139    /// Any previously generated Result values remain valid.
140    /// (This does not require that any previous results returned remain in the results vector, as it is
141    /// appended to without examining the existing contents)
142    ///
143    /// If this does not return an error, results will contain at least one Result, and potentially
144    /// more if the inputs are slower than the minimum output rate
145    pub fn update(&mut self, input: ModelerInput) -> Result<Vec<ModelerResult>, ModelerError> {
146        match input.event_type {
147            ModelerInputEventType::Down => {
148                if self.last_event.is_some() {
149                    return Err(ModelerError::Element {
150                        src: ElementError::Order {
151                            src: ElementOrderError::UnexpectedDown,
152                        },
153                    });
154                }
155                self.wobble_update(&input); // first event is "as is"
156
157                self.position_modeler = Some(PositionModeler::new(self.params, input.clone()));
158
159                self.last_event = Some(input.clone());
160                self.last_corrected_event = Some(input.pos);
161                self.state_modeler
162                    .reset(self.params.stylus_state_modeler_max_input_samples);
163                self.state_modeler.update(input.clone());
164                Ok(vec![ModelerResult {
165                    pos: input.pos,
166                    velocity: (0.0, 0.0),
167                    acceleration: (0.0, 0.0),
168                    time: input.time,
169                    pressure: input.pressure,
170                }])
171            }
172            ModelerInputEventType::Move => {
173                // get the latest element
174                if self.last_event.is_none() {
175                    return Err(ModelerError::Element {
176                        src: ElementError::Order {
177                            src: ElementOrderError::UnexpectedMove,
178                        },
179                    });
180                }
181                let latest_time = self.last_event.as_ref().unwrap().time;
182                let new_time = input.time;
183
184                // validate before doing anything
185                // if the input is incorrect, return an error and leave the engine unmodified
186                if new_time - latest_time < 0.0 {
187                    return Err(ModelerError::Element {
188                        src: ElementError::NegativeTimeDelta,
189                    });
190                }
191                if input == *self.last_event.as_ref().unwrap() {
192                    return Err(ModelerError::Element {
193                        src: ElementError::Duplicate,
194                    });
195                }
196
197                self.state_modeler.update(input.clone());
198
199                // calculate the number of element to predict
200                let n_steps =
201                    ((new_time - latest_time) * self.params.sampling_min_output_rate).ceil() as i32;
202
203                // this errors if the number of steps is larger than
204                // [ModelParams::sampling_max_outputs_per_call]
205                if n_steps as usize > self.params.sampling_max_outputs_per_call {
206                    return Err(ModelerError::Element {
207                        src: ElementError::TooFarApart,
208                    });
209                }
210
211                let p_start = self.last_corrected_event.unwrap();
212                let p_end = self.wobble_update(&input);
213                // seems like speeds are way higher than normal speed encountered so no smoothing occurs here
214
215                let vec_out: Vec<ModelerResult> = self
216                    .position_modeler
217                    .as_mut()
218                    .unwrap()
219                    .update_along_linear_path(p_start, latest_time, p_end, new_time, n_steps)
220                    .into_iter()
221                    .map(|i| ModelerResult {
222                        pressure: self.state_modeler.query(i.pos),
223                        pos: i.pos,
224                        velocity: i.velocity,
225                        acceleration: i.acceleration,
226                        time: i.time,
227                    })
228                    .collect();
229
230                // push the latest element (should we push everything we also interpolated as well ?)
231                self.last_event = Some(input.clone());
232                self.last_corrected_event = Some(p_end);
233
234                Ok(vec_out)
235            }
236            ModelerInputEventType::Up => {
237                // get the latest element
238                if self.last_event.is_none() {
239                    return Err(ModelerError::Element {
240                        src: ElementError::Order {
241                            src: ElementOrderError::UnexpectedUp,
242                        },
243                    });
244                }
245                let latest_time = self.last_event.as_ref().unwrap().time;
246                let new_time = input.time;
247
248                // validate before doing any changes to the modeler
249                if new_time - latest_time < 0.0 {
250                    return Err(ModelerError::Element {
251                        src: ElementError::NegativeTimeDelta,
252                    });
253                }
254                if input == *self.last_event.as_ref().unwrap() {
255                    return Err(ModelerError::Element {
256                        src: ElementError::Duplicate,
257                    });
258                }
259
260                self.state_modeler.update(input.clone());
261
262                // calculate the number of element to predict
263                let n_tsteps =
264                    ((new_time - latest_time) * self.params.sampling_min_output_rate).ceil() as i32;
265
266                // this errors if the number of steps is larger than
267                // [ModelParams::sampling_max_outputs_per_call]
268                if n_tsteps as usize > self.params.sampling_max_outputs_per_call {
269                    return Err(ModelerError::Element {
270                        src: ElementError::TooFarApart,
271                    });
272                }
273
274                let p_start = self.last_corrected_event.unwrap();
275                // the p_end is purposefully different from the original implementation
276                // to match the Move part
277                // the original takes the raw input here which means a different
278                // behavior between the predict on a Move and a Up
279                let p_end = self.wobble_update(&input);
280
281                let mut vec_out = Vec::<ModelerResult>::with_capacity(
282                    (n_tsteps as usize) + self.params.sampling_end_of_stroke_max_iterations,
283                );
284
285                vec_out.extend(
286                    self.position_modeler
287                        .as_mut()
288                        .unwrap()
289                        .update_along_linear_path(p_start, latest_time, p_end, new_time, n_tsteps)
290                        .into_iter()
291                        .map(|i| ModelerResult {
292                            pressure: self.state_modeler.query(i.pos),
293                            pos: i.pos,
294                            velocity: i.velocity,
295                            time: i.time,
296                            acceleration: i.acceleration,
297                        }),
298                );
299
300                // model the end of stroke
301                vec_out.extend(
302                    self.position_modeler
303                        .as_mut()
304                        .unwrap()
305                        .model_end_of_stroke(
306                            input.pos,
307                            1. / self.params.sampling_min_output_rate,
308                            self.params.sampling_end_of_stroke_max_iterations,
309                            self.params.sampling_end_of_stroke_stopping_distance,
310                        )
311                        .into_iter()
312                        .map(|i| ModelerResult {
313                            pressure: self.state_modeler.query(i.pos),
314                            pos: i.pos,
315                            velocity: i.velocity,
316                            acceleration: i.acceleration,
317                            time: i.time,
318                        }),
319                );
320
321                if vec_out.is_empty() {
322                    let state_pos = self.position_modeler.as_ref().unwrap().state.clone();
323                    vec_out.push(ModelerResult {
324                        pos: state_pos.pos,
325                        velocity: state_pos.velocity,
326                        acceleration: state_pos.acceleration,
327                        // this is so that the extra stroke added has a time that's larger than the previous one
328                        // when the Up happens at the same time as the Move
329                        // In the original implementation, this was always true because
330                        // the ModelEndOfStroke function did not restore the state of the modeler
331                        // so that even if a single candidate was tried and iterations stopped there
332                        // the status of the modeler changed, including the time by at least
333                        // `1. / self.params.sampling_min_output_rate`
334                        time: state_pos.time + 1. / self.params.sampling_min_output_rate,
335                        pressure: self.state_modeler.query(state_pos.pos),
336                    });
337                }
338
339                // remove the last event
340                self.last_event = None;
341
342                Ok(vec_out)
343            }
344        }
345    }
346
347    /// Models the given input prediction without changing the internal model state
348    ///
349    /// Returns an error if the model has not yet been initialized,
350    /// if there is no stroke in progress
351    pub fn predict(&mut self) -> Result<Vec<ModelerResult>, String> {
352        // for now return the latest element if it exists from the input
353        if self.last_event.is_none() {
354            // no data to predict from
355            Err(String::from("empty input events"))
356        } else {
357            // construct the prediction (model_end_of_stroke does not modify the position modeler)
358            let predict = self
359                .position_modeler
360                .as_mut()
361                .unwrap()
362                .model_end_of_stroke(
363                    self.last_event.as_ref().unwrap().pos,
364                    1. / self.params.sampling_min_output_rate,
365                    self.params.sampling_end_of_stroke_max_iterations,
366                    self.params.sampling_end_of_stroke_stopping_distance,
367                )
368                .into_iter()
369                .map(|i| ModelerResult {
370                    pos: i.pos,
371                    velocity: i.velocity,
372                    acceleration: i.acceleration,
373                    time: i.time,
374                    pressure: self.state_modeler.query(i.pos),
375                })
376                .collect();
377            Ok(predict)
378        }
379    }
380    ///implements the wobble logic
381    ///smoothes out the input position from high frequency noise
382    ///uses a moving average of position and interpolating between this
383    ///position and the raw position based on the speed.
384    ///high speeds movements won't be smoothed but low speed will.
385    #[doc = include_str!("../docs/wobble.html")]
386    fn wobble_update(&mut self, event: &ModelerInput) -> (f64, f64) {
387        match self.wobble_deque.len() {
388            0 => {
389                self.wobble_deque.push_back(WobbleSample {
390                    position: event.pos,
391                    weighted_position: (0.0, 0.0),
392                    distance: 0.0,
393                    duration: 0.0,
394                    time: event.time,
395                });
396                event.pos
397            }
398            _ => {
399                let last_el = self.wobble_deque.back().unwrap();
400                let duration = event.time - last_el.time;
401                let weighted_pos = (event.pos.0 * duration, event.pos.1 * duration);
402                let distance = ((event.pos.0 - last_el.position.0).powi(2)
403                    + (event.pos.1 - last_el.position.1).powi(2))
404                .sqrt();
405
406                self.wobble_deque.push_back(WobbleSample {
407                    position: event.pos,
408                    weighted_position: weighted_pos,
409                    distance,
410                    duration,
411                    time: event.time,
412                });
413                let last_pos = self.wobble_weighted_pos_sum;
414                self.wobble_weighted_pos_sum =
415                    (last_pos.0 + weighted_pos.0, last_pos.1 + weighted_pos.1);
416                self.wobble_distance_sum += distance;
417                self.wobble_duration_sum += duration;
418
419                while self.wobble_deque.front().unwrap().time
420                    < event.time - self.params.wobble_smoother_timeout
421                {
422                    let front_el = self.wobble_deque.pop_front().unwrap();
423
424                    let last_pos = self.wobble_weighted_pos_sum;
425                    self.wobble_weighted_pos_sum = (
426                        last_pos.0 - front_el.weighted_position.0,
427                        last_pos.1 - front_el.weighted_position.1,
428                    );
429                    self.wobble_distance_sum -= front_el.distance;
430                    self.wobble_duration_sum -= front_el.duration;
431                }
432
433                if self.wobble_duration_sum < 1e-12 {
434                    event.pos
435                } else {
436                    // calculate the average position
437
438                    let avg_position = (
439                        self.wobble_weighted_pos_sum.0 / self.wobble_duration_sum,
440                        self.wobble_weighted_pos_sum.1 / self.wobble_duration_sum,
441                    );
442
443                    let avg_speed = self.wobble_distance_sum / self.wobble_duration_sum;
444                    let norm_value = normalize01_64(
445                        self.params.wobble_smoother_speed_floor,
446                        self.params.wobble_smoother_speed_ceiling,
447                        avg_speed,
448                    );
449                    (
450                        interp(avg_position.0, event.pos.0, norm_value),
451                        interp(avg_position.1, event.pos.1, norm_value),
452                    )
453                }
454            }
455        }
456    }
457}
458
459#[cfg(test)]
460mod tests {
461
462    use super::super::*;
463    use crate::results::compare_results;
464
465    /// compare (f64,f64) floats up to `0.0001` precision
466    /// utility for testing only
467    #[cfg(test)]
468    fn util_compare_floats(a1: (f64, f64), a2: (f64, f64)) -> bool {
469        return approx::abs_diff_eq!(a1.0, a2.0, epsilon = 0.0001)
470            && approx::abs_diff_eq!(a1.1, a2.1, epsilon = 0.0001);
471    }
472
473    // wobble tests
474
475    #[test]
476    fn test_wobble_smoother_line() {
477        // need to create a StrokeModeler
478        let mut new_modeler = StrokeModeler::default();
479        new_modeler.wobble_update(&ModelerInput {
480            event_type: ModelerInputEventType::Down,
481            pos: (3., 4.),
482            time: 1.0,
483            pressure: 0.0,
484        });
485        assert!(util_compare_floats(
486            new_modeler.wobble_update(&ModelerInput {
487                event_type: ModelerInputEventType::Move,
488                pos: (3.016, 4.),
489                time: 1.016,
490                pressure: 0.0,
491            }),
492            (3.016, 4.)
493        ));
494        assert!(util_compare_floats(
495            new_modeler.wobble_update(&ModelerInput {
496                event_type: ModelerInputEventType::Move,
497                pos: (3.032, 4.),
498                time: 1.032,
499                pressure: 0.0,
500            }),
501            (3.024, 4.)
502        ));
503        assert!(util_compare_floats(
504            new_modeler.wobble_update(&ModelerInput {
505                event_type: ModelerInputEventType::Move,
506                pos: (3.048, 4.),
507                time: 1.048,
508                pressure: 0.0,
509            }),
510            (3.032, 4.)
511        ));
512        assert!(util_compare_floats(
513            new_modeler.wobble_update(&ModelerInput {
514                event_type: ModelerInputEventType::Move,
515                pos: (3.064, 4.),
516                time: 1.064,
517                pressure: 0.0,
518            }),
519            (3.048, 4.)
520        ));
521    }
522
523    #[test]
524    fn test_wobble_zigzag_slow() {
525        // need to create a StrokeModeler
526        let mut new_modeler = StrokeModeler::default();
527        new_modeler.wobble_update(&ModelerInput {
528            event_type: ModelerInputEventType::Down,
529            pos: (1., 2.),
530            time: 5.0,
531            pressure: 0.0,
532        });
533        assert!(util_compare_floats(
534            new_modeler.wobble_update(&ModelerInput {
535                event_type: ModelerInputEventType::Move,
536                pos: (1.016, 2.),
537                time: 5.016,
538                pressure: 0.0,
539            }),
540            (1.016, 2.0)
541        ));
542        assert!(util_compare_floats(
543            new_modeler.wobble_update(&ModelerInput {
544                event_type: ModelerInputEventType::Move,
545                pos: (1.016, 2.016),
546                time: 5.032,
547                pressure: 0.0,
548            }),
549            (1.016, 2.008)
550        ));
551        assert!(util_compare_floats(
552            new_modeler.wobble_update(&ModelerInput {
553                event_type: ModelerInputEventType::Move,
554                pos: (1.032, 2.016),
555                time: 5.048,
556                pressure: 0.0,
557            }),
558            (1.02133, 2.01067)
559        ));
560        assert!(util_compare_floats(
561            new_modeler.wobble_update(&ModelerInput {
562                event_type: ModelerInputEventType::Move,
563                pos: (1.032, 2.032),
564                time: 5.064,
565                pressure: 0.0,
566            }),
567            (1.0266667, 2.0213333)
568        ));
569        assert!(util_compare_floats(
570            new_modeler.wobble_update(&ModelerInput {
571                event_type: ModelerInputEventType::Move,
572                pos: (1.048, 2.032),
573                time: 5.080,
574                pressure: 0.0,
575            }),
576            (1.0373333, 2.0266667)
577        ));
578        assert!(util_compare_floats(
579            new_modeler.wobble_update(&ModelerInput {
580                event_type: ModelerInputEventType::Move,
581                pos: (1.048, 2.048),
582                time: 5.096,
583                pressure: 0.0,
584            }),
585            (1.0426667, 2.0373333)
586        ));
587    }
588
589    #[test]
590    fn fast_zigzag() {
591        let mut new_modeler = StrokeModeler::default();
592        assert!(util_compare_floats(
593            new_modeler.wobble_update(&ModelerInput {
594                event_type: ModelerInputEventType::Move,
595                pos: (7., 3.024),
596                time: 8.016,
597                pressure: 0.0,
598            }),
599            (7.0, 3.024)
600        ));
601        assert!(util_compare_floats(
602            new_modeler.wobble_update(&ModelerInput {
603                event_type: ModelerInputEventType::Move,
604                pos: (7.024, 3.024),
605                time: 8.032,
606                pressure: 0.0,
607            }),
608            (7.024, 3.024)
609        ));
610        assert!(util_compare_floats(
611            new_modeler.wobble_update(&ModelerInput {
612                event_type: ModelerInputEventType::Move,
613                pos: (7.024, 3.048),
614                time: 8.048,
615                pressure: 0.0,
616            }),
617            (7.024, 3.048)
618        ));
619        assert!(util_compare_floats(
620            new_modeler.wobble_update(&ModelerInput {
621                event_type: ModelerInputEventType::Move,
622                pos: (7.048, 3.048),
623                time: 8.064,
624                pressure: 0.0,
625            }),
626            (7.048, 3.048)
627        ));
628    }
629
630    #[test]
631    fn input_test() {
632        let mut modeler = StrokeModeler::new(ModelerParams::suggested()).unwrap();
633
634        let inputs = vec![
635            ModelerInput {
636                event_type: ModelerInputEventType::Down,
637                pos: (0.0, 0.0),
638                time: 0.0,
639                pressure: 0.1,
640            },
641            ModelerInput {
642                event_type: ModelerInputEventType::Move,
643                pos: (1.0, 0.0),
644                time: 0.02,
645                pressure: 0.3,
646            },
647            ModelerInput {
648                event_type: ModelerInputEventType::Move,
649                pos: (2.0, 0.0),
650                time: 0.04,
651                pressure: 0.5,
652            },
653            ModelerInput {
654                event_type: ModelerInputEventType::Move,
655                pos: (2.5, 1.0),
656                time: 0.06,
657                pressure: 0.8,
658            },
659            ModelerInput {
660                event_type: ModelerInputEventType::Move,
661                pos: (3.0, 1.5),
662                time: 0.12,
663                pressure: 0.9,
664            },
665            ModelerInput {
666                event_type: ModelerInputEventType::Move,
667                pos: (4.0, 2.0),
668                time: 0.13,
669                pressure: 0.8,
670            },
671            ModelerInput {
672                event_type: ModelerInputEventType::Move,
673                pos: (3.8, 2.1),
674                time: 0.14,
675                pressure: 0.7,
676            },
677            ModelerInput {
678                event_type: ModelerInputEventType::Up,
679                pos: (3.5, 2.0),
680                time: 0.14,
681                pressure: 0.2,
682            },
683        ];
684
685        for res in inputs.into_iter().flat_map(|i| modeler.update(i)) {
686            println!("{res:?}");
687        }
688    }
689
690    //tests for the end of stroke prediction
691    #[test]
692    fn test_empty_prediction() {
693        let mut engine = StrokeModeler::new(ModelerParams::suggested()).unwrap();
694        assert!(engine.predict().is_err());
695    }
696
697    #[test]
698    fn test_singleinput() {
699        let mut engine = StrokeModeler::default();
700        engine
701            .update(ModelerInput {
702                pos: (4.0, 5.0),
703                event_type: ModelerInputEventType::Down,
704                time: 2.0,
705                pressure: 1.0,
706            })
707            .unwrap();
708        assert_eq!(engine.predict().unwrap().len(), 0);
709    }
710
711    // tests for the stroke modeler
712    #[test]
713    fn input_rate_slower() {
714        // ceil is exactly on the limit making it different from the original test without this cast
715        let delta_time = (1. / 30. as f32) as f64;
716        let mut time = 0.0;
717        let mut engine = StrokeModeler::new(ModelerParams {
718            stylus_state_modeler_max_input_samples: 20,
719            ..ModelerParams::suggested()
720        })
721        .unwrap();
722
723        let first_iter = engine.update(ModelerInput {
724            event_type: ModelerInputEventType::Down,
725            pos: (3., 4.),
726            time: time,
727            pressure: 1.0,
728        });
729        assert!(first_iter.is_ok());
730        assert!(compare_results(
731            first_iter.unwrap(),
732            vec![ModelerResult {
733                pos: (3.0, 4.0),
734                ..ModelerResult::default()
735            }]
736        ));
737
738        assert!(engine.predict().is_ok());
739        assert!(engine.predict().unwrap().is_empty());
740
741        time += delta_time;
742        assert!(compare_results(
743            engine
744                .update(ModelerInput {
745                    event_type: ModelerInputEventType::Move,
746                    pos: (3.2, 4.2),
747                    time: time,
748                    pressure: 1.0
749                })
750                .unwrap(),
751            vec![
752                ModelerResult {
753                    pos: (3.0019, 4.0019),
754                    velocity: (0.4007, 0.4007),
755                    acceleration: (84.1557, 84.1564),
756                    time: 0.0048,
757                    pressure: 1.0
758                },
759                ModelerResult {
760                    pos: (3.0069, 4.0069),
761                    velocity: (1.0381, 1.0381),
762                    acceleration: (133.8378, 133.8369),
763                    time: 0.0095,
764                    pressure: 1.0
765                },
766                ModelerResult {
767                    pos: (3.0154, 4.0154),
768                    velocity: (1.7883, 1.7883),
769                    acceleration: (157.5465, 157.5459),
770                    time: 0.0143,
771                    pressure: 1.0
772                },
773                ModelerResult {
774                    pos: (3.0276, 4.0276),
775                    velocity: (2.5626, 2.5626),
776                    acceleration: (162.6039, 162.6021),
777                    time: 0.0190,
778                    pressure: 1.0
779                },
780                ModelerResult {
781                    pos: (3.0433, 4.0433),
782                    velocity: (3.3010, 3.3010),
783                    acceleration: (155.0670, 155.0666),
784                    time: 0.0238,
785                    pressure: 1.0
786                },
787                ModelerResult {
788                    pos: (3.0622, 4.0622),
789                    velocity: (3.9665, 3.9665),
790                    acceleration: (139.7575, 139.7564),
791                    time: 0.0286,
792                    pressure: 1.0
793                },
794                ModelerResult {
795                    pos: (3.0838, 4.0838),
796                    velocity: (4.5397, 4.5397),
797                    acceleration: (120.3618, 120.3625),
798                    time: 0.0333,
799                    pressure: 1.0
800                }
801            ]
802        ));
803
804        assert!(engine.predict().is_ok());
805        assert!(compare_results(
806            engine.predict().unwrap(),
807            vec![
808                ModelerResult {
809                    pos: (3.1095, 4.1095),
810                    velocity: (4.6253, 4.6253),
811                    acceleration: (15.4218, 15.4223),
812                    time: 0.0389,
813                    pressure: 1.0
814                },
815                ModelerResult {
816                    pos: (3.1331, 4.1331),
817                    velocity: (4.2563, 4.2563),
818                    acceleration: (-66.4341, -66.4339),
819                    time: 0.0444,
820                    pressure: 1.0
821                },
822                ModelerResult {
823                    pos: (3.1534, 4.1534),
824                    velocity: (3.6479, 3.6479),
825                    acceleration: (-109.5083, -109.5081),
826                    time: 0.0500,
827                    pressure: 1.0
828                },
829                ModelerResult {
830                    pos: (3.1698, 4.1698),
831                    velocity: (2.9512, 2.9512),
832                    acceleration: (-125.3978, -125.3976),
833                    time: 0.0556,
834                    pressure: 1.0
835                },
836                ModelerResult {
837                    pos: (3.1824, 4.1824),
838                    velocity: (2.2649, 2.2649),
839                    acceleration: (-123.5318, -123.5310),
840                    time: 0.0611,
841                    pressure: 1.0
842                },
843                ModelerResult {
844                    pos: (3.1915, 4.1915),
845                    velocity: (1.6473, 1.6473),
846                    acceleration: (-111.1818, -111.1806),
847                    time: 0.0667,
848                    pressure: 1.0
849                },
850                ModelerResult {
851                    pos: (3.1978, 4.1978),
852                    velocity: (1.1269, 1.1269),
853                    acceleration: (-93.6643, -93.6636),
854                    time: 0.0722,
855                    pressure: 1.0
856                },
857                ModelerResult {
858                    pos: (3.1992, 4.1992),
859                    velocity: (1.0232, 1.0232),
860                    acceleration: (-74.6390, -74.6392),
861                    time: 0.0736,
862                    pressure: 1.0
863                }
864            ]
865        ));
866
867        time += delta_time;
868        let second_results = engine.update(ModelerInput {
869            event_type: ModelerInputEventType::Move,
870            pos: (3.5, 4.2),
871            time: time,
872            pressure: 1.0,
873        });
874        assert!(second_results.is_ok());
875        assert!(compare_results(
876            second_results.unwrap(),
877            vec![
878                ModelerResult {
879                    pos: (3.1086, 4.1058),
880                    velocity: (5.2142, 4.6131),
881                    acceleration: (141.6557, 15.4223),
882                    time: 0.0381,
883                    pressure: 1.0
884                },
885                ModelerResult {
886                    pos: (3.1368, 4.1265),
887                    velocity: (5.9103, 4.3532),
888                    acceleration: (146.1873, -54.5680),
889                    time: 0.0429,
890                    pressure: 1.0
891                },
892                ModelerResult {
893                    pos: (3.1681, 4.1450),
894                    velocity: (6.5742, 3.8917),
895                    acceleration: (139.4012, -96.9169),
896                    time: 0.0476,
897                    pressure: 1.0
898                },
899                ModelerResult {
900                    pos: (3.2022, 4.1609),
901                    velocity: (7.1724, 3.3285),
902                    acceleration: (125.6306, -118.2742),
903                    time: 0.0524,
904                    pressure: 1.0
905                },
906                ModelerResult {
907                    pos: (3.2388, 4.1739),
908                    velocity: (7.6876, 2.7361),
909                    acceleration: (108.1908, -124.4087),
910                    time: 0.0571,
911                    pressure: 1.0
912                },
913                ModelerResult {
914                    pos: (3.2775, 4.1842),
915                    velocity: (8.1138, 2.1640),
916                    acceleration: (89.5049, -120.1309),
917                    time: 0.0619,
918                    pressure: 1.0
919                },
920                ModelerResult {
921                    pos: (3.3177, 4.1920),
922                    velocity: (8.4531, 1.6436),
923                    acceleration: (71.2473, -109.2959),
924                    time: 0.0667,
925                    pressure: 1.0
926                }
927            ]
928        ));
929
930        assert!(engine.predict().is_ok());
931        assert!(compare_results(
932            engine.predict().unwrap(),
933            vec![
934                ModelerResult {
935                    pos: (3.3625, 4.1982),
936                    velocity: (8.0545, 1.1165),
937                    acceleration: (-71.7427, -94.8765),
938                    time: 0.0722,
939                    pressure: 1.0
940                },
941                ModelerResult {
942                    pos: (3.4018, 4.2021),
943                    velocity: (7.0831, 0.6987),
944                    acceleration: (-174.8469, -75.1957),
945                    time: 0.0778,
946                    pressure: 1.0
947                },
948                ModelerResult {
949                    pos: (3.4344, 4.2043),
950                    velocity: (5.8564, 0.3846),
951                    acceleration: (-220.8140, -56.5515),
952                    time: 0.0833,
953                    pressure: 1.0
954                },
955                ModelerResult {
956                    pos: (3.4598, 4.2052),
957                    velocity: (4.5880, 0.1611),
958                    acceleration: (-228.3204, -40.2244),
959                    time: 0.0889,
960                    pressure: 1.0
961                },
962                ModelerResult {
963                    pos: (3.4788, 4.2052),
964                    velocity: (3.4098, 0.0124),
965                    acceleration: (-212.0678, -26.7709),
966                    time: 0.0944,
967                    pressure: 1.0
968                },
969                ModelerResult {
970                    pos: (3.4921, 4.2048),
971                    velocity: (2.3929, -0.0780),
972                    acceleration: (-183.0373, -16.2648),
973                    time: 0.1000,
974                    pressure: 1.0
975                },
976                ModelerResult {
977                    pos: (3.4976, 4.2045),
978                    velocity: (1.9791, -0.1015),
979                    acceleration: (-148.9792, -8.4822),
980                    time: 0.1028,
981                    pressure: 1.0
982                },
983                ModelerResult {
984                    pos: (3.5001, 4.2044),
985                    velocity: (1.7911, -0.1098),
986                    acceleration: (-135.3759, -5.9543),
987                    time: 0.1042,
988                    pressure: 1.0
989                }
990            ]
991        ));
992
993        // we get more strokes as the model catches up to the anchor position
994        time += delta_time;
995        let update = engine.update(ModelerInput {
996            event_type: ModelerInputEventType::Up,
997            pos: (3.7, 4.4),
998            time: time,
999            pressure: 1.0,
1000        });
1001        assert!(update.is_ok());
1002        assert!(compare_results(
1003            update.unwrap(),
1004            vec![
1005                ModelerResult {
1006                    pos: (3.3583, 4.1996),
1007                    velocity: (8.5122, 1.5925),
1008                    acceleration: (12.4129, -10.7201),
1009                    time: 0.0714,
1010                    pressure: 1.0
1011                },
1012                ModelerResult {
1013                    pos: (3.3982, 4.2084),
1014                    velocity: (8.3832, 1.8534),
1015                    acceleration: (-27.0783, 54.7731),
1016                    time: 0.0762,
1017                    pressure: 1.0
1018                },
1019                ModelerResult {
1020                    pos: (3.4369, 4.2194),
1021                    velocity: (8.1393, 2.3017),
1022                    acceleration: (-51.2222, 94.1542),
1023                    time: 0.0810,
1024                    pressure: 1.0
1025                },
1026                ModelerResult {
1027                    pos: (3.4743, 4.2329),
1028                    velocity: (7.8362, 2.8434),
1029                    acceleration: (-63.6668, 113.7452),
1030                    time: 0.0857,
1031                    pressure: 1.0
1032                },
1033                ModelerResult {
1034                    pos: (3.5100, 4.2492),
1035                    velocity: (7.5143, 3.4101),
1036                    acceleration: (-67.5926, 119.0224),
1037                    time: 0.0905,
1038                    pressure: 1.0
1039                },
1040                ModelerResult {
1041                    pos: (3.5443, 4.2680),
1042                    velocity: (7.2016, 3.9556),
1043                    acceleration: (-65.6568, 114.5394),
1044                    time: 0.0952,
1045                    pressure: 1.0
1046                },
1047                ModelerResult {
1048                    pos: (3.5773, 4.2892),
1049                    velocity: (6.9159, 4.4505),
1050                    acceleration: (-59.9999, 103.9444),
1051                    time: 0.1000,
1052                    pressure: 1.0
1053                },
1054                ModelerResult {
1055                    pos: (3.6115, 4.3141),
1056                    velocity: (6.1580, 4.4832),
1057                    acceleration: (-136.4312, 5.8833),
1058                    time: 0.1056,
1059                    pressure: 1.0
1060                },
1061                ModelerResult {
1062                    pos: (3.6400, 4.3369),
1063                    velocity: (5.1434, 4.0953),
1064                    acceleration: (-182.6254, -69.8314),
1065                    time: 0.1111,
1066                    pressure: 1.0
1067                },
1068                ModelerResult {
1069                    pos: (3.6626, 4.3563),
1070                    velocity: (4.0671, 3.4902),
1071                    acceleration: (-193.7401, -108.9119),
1072                    time: 0.1167,
1073                    pressure: 1.0
1074                },
1075                ModelerResult {
1076                    pos: (3.6796, 4.3719),
1077                    velocity: (3.0515, 2.8099),
1078                    acceleration: (-182.7957, -122.4598),
1079                    time: 0.1222,
1080                    pressure: 1.0
1081                },
1082                ModelerResult {
1083                    pos: (3.6916, 4.3838),
1084                    velocity: (2.1648, 2.1462),
1085                    acceleration: (-159.6116, -119.4551),
1086                    time: 0.1278,
1087                    pressure: 1.0
1088                },
1089                ModelerResult {
1090                    pos: (3.6996, 4.3924),
1091                    velocity: (1.4360, 1.5529),
1092                    acceleration: (-131.1906, -106.7926),
1093                    time: 0.1333,
1094                    pressure: 1.0
1095                },
1096                ModelerResult {
1097                    pos: (3.7028, 4.3960),
1098                    velocity: (1.1520, 1.3044),
1099                    acceleration: (-102.2117, -89.4872),
1100                    time: 0.1361,
1101                    pressure: 1.0
1102                }
1103            ]
1104        ));
1105
1106        // the stroke is finished, we get an error if we predict it
1107        assert!(engine.predict().is_err());
1108    }
1109
1110    #[test]
1111    fn reset_keep_params() {
1112        let input = ModelerInput {
1113            event_type: ModelerInputEventType::Down,
1114            pos: (3.0, 4.0),
1115            time: 0.0,
1116            pressure: 1.0,
1117        };
1118        let mut engine = StrokeModeler::default();
1119        assert!(engine.update(input.clone()).is_ok());
1120
1121        assert!(engine.reset_w_params(ModelerParams::suggested()).is_ok());
1122        assert!(engine.update(input.clone()).is_ok());
1123    }
1124
1125    /// InputRateFasterThanMinOutputRate
1126    #[test]
1127    fn input_rate_faster() {
1128        let delta_time = 1. / 300.;
1129        let mut engine = StrokeModeler::default();
1130
1131        let mut time = 2.0;
1132
1133        let res1 = engine.update(ModelerInput {
1134            event_type: ModelerInputEventType::Down,
1135            pos: (5.0, -3.0),
1136            time: time,
1137            pressure: 1.0,
1138        });
1139
1140        assert!(res1.is_ok());
1141        assert!(compare_results(
1142            res1.unwrap(),
1143            vec![ModelerResult {
1144                pos: (5.0, -3.0),
1145                time: time,
1146                velocity: (0.0, 0.0),
1147                acceleration: (0.0, 0.0),
1148                pressure: 1.0
1149            }]
1150        ));
1151
1152        assert!(engine.predict().is_ok());
1153        assert!(engine.predict().unwrap().is_empty());
1154
1155        time += delta_time;
1156        let res2 = engine.update(ModelerInput {
1157            event_type: ModelerInputEventType::Move,
1158            pos: (5.0, -3.1),
1159            time: time,
1160            pressure: 1.0,
1161        });
1162        assert!(res2.is_ok());
1163        assert!(compare_results(
1164            res2.unwrap(),
1165            vec![ModelerResult {
1166                pos: (5.0, -3.0033),
1167                velocity: (0.0, -0.9818),
1168                acceleration: (0.0, -294.5452),
1169                time: 2.0033,
1170                pressure: 1.0
1171            }]
1172        ));
1173
1174        assert!(compare_results(
1175            engine.predict().unwrap(),
1176            vec![
1177                ModelerResult {
1178                    pos: (5.0, -3.0153),
1179                    velocity: (0.0, -2.1719),
1180                    acceleration: (0.0, -214.2145),
1181                    time: 2.0089,
1182                    pressure: 1.0
1183                },
1184                ModelerResult {
1185                    pos: (5.0, -3.0303),
1186                    velocity: (0.0, -2.6885),
1187                    acceleration: (0.0, -92.9885),
1188                    time: 2.0144,
1189                    pressure: 1.0
1190                },
1191                ModelerResult {
1192                    pos: (5.0, -3.0456),
1193                    velocity: (0.0, -2.7541),
1194                    acceleration: (0.0, -11.7992),
1195                    time: 2.0200,
1196                    pressure: 1.0
1197                },
1198                ModelerResult {
1199                    pos: (5.0, -3.0597),
1200                    velocity: (0.0, -2.5430),
1201                    acceleration: (0.0, 37.9868),
1202                    time: 2.0256,
1203                    pressure: 1.0
1204                },
1205                ModelerResult {
1206                    pos: (5.0, -3.0718),
1207                    velocity: (0.0, -2.1852),
1208                    acceleration: (0.0, 64.4053),
1209                    time: 2.0311,
1210                    pressure: 1.0
1211                },
1212                ModelerResult {
1213                    pos: (5.0, -3.0817),
1214                    velocity: (0.0, -1.7719),
1215                    acceleration: (0.0, 74.4011),
1216                    time: 2.0367,
1217                    pressure: 1.0
1218                },
1219                ModelerResult {
1220                    pos: (5.0, -3.0893),
1221                    velocity: (0.0, -1.3628),
1222                    acceleration: (0.0, 73.6345),
1223                    time: 2.0422,
1224                    pressure: 1.0
1225                },
1226                ModelerResult {
1227                    pos: (5.0, -3.0948),
1228                    velocity: (0.0, -0.9934),
1229                    acceleration: (0.0, 66.4807),
1230                    time: 2.0478,
1231                    pressure: 1.0
1232                },
1233                ModelerResult {
1234                    pos: (5.0, -3.0986),
1235                    velocity: (0.0, -0.6815),
1236                    acceleration: (0.0, 56.1448),
1237                    time: 2.0533,
1238                    pressure: 1.0
1239                }
1240            ]
1241        ));
1242        assert!(engine.predict().is_ok());
1243
1244        time += delta_time;
1245
1246        let res3 = engine.update(ModelerInput {
1247            event_type: ModelerInputEventType::Move,
1248            pos: (4.975, -3.175),
1249            time: time,
1250            pressure: 1.0,
1251        });
1252        assert!(res3.is_ok());
1253        assert!(compare_results(
1254            res3.unwrap(),
1255            vec![ModelerResult {
1256                pos: (4.9992, -3.0114),
1257                velocity: (-0.2455, -2.4322),
1258                acceleration: (-73.6366, -435.1238),
1259                time: 2.0067,
1260                pressure: 1.0
1261            }]
1262        ));
1263
1264        assert!(engine.predict().is_ok());
1265        assert!(compare_results(
1266            engine.predict().unwrap(),
1267            vec![
1268                ModelerResult {
1269                    pos: (4.9962, -3.0344),
1270                    velocity: (-0.5430, -4.1368),
1271                    acceleration: (-53.5537, -306.8140),
1272                    time: 2.0122,
1273                    pressure: 1.0
1274                },
1275                ModelerResult {
1276                    pos: (4.9924, -3.0609),
1277                    velocity: (-0.6721, -4.7834),
1278                    acceleration: (-23.2474, -116.3963),
1279                    time: 2.0178,
1280                    pressure: 1.0
1281                },
1282                ModelerResult {
1283                    pos: (4.9886, -3.0873),
1284                    velocity: (-0.6885, -4.7365),
1285                    acceleration: (-2.9498, 8.4358),
1286                    time: 2.0233,
1287                    pressure: 1.0
1288                },
1289                ModelerResult {
1290                    pos: (4.9851, -3.1110),
1291                    velocity: (-0.6358, -4.2778),
1292                    acceleration: (9.4971, 82.5682),
1293                    time: 2.0289,
1294                    pressure: 1.0
1295                },
1296                ModelerResult {
1297                    pos: (4.9820, -3.1311),
1298                    velocity: (-0.5463, -3.6137),
1299                    acceleration: (16.1014, 119.5413),
1300                    time: 2.0344,
1301                    pressure: 1.0
1302                },
1303                ModelerResult {
1304                    pos: (4.9796, -3.1471),
1305                    velocity: (-0.4430, -2.8867),
1306                    acceleration: (18.6005, 130.8578),
1307                    time: 2.0400,
1308                    pressure: 1.0
1309                },
1310                ModelerResult {
1311                    pos: (4.9777, -3.1593),
1312                    velocity: (-0.3407, -2.1881),
1313                    acceleration: (18.4089, 125.7516),
1314                    time: 2.0456,
1315                    pressure: 1.0
1316                },
1317                ModelerResult {
1318                    pos: (4.9763, -3.1680),
1319                    velocity: (-0.2484, -1.5700),
1320                    acceleration: (16.6198, 111.2560),
1321                    time: 2.0511,
1322                    pressure: 1.0
1323                },
1324                ModelerResult {
1325                    pos: (4.9754, -3.1739),
1326                    velocity: (-0.1704, -1.0564),
1327                    acceleration: (14.0365, 92.4447),
1328                    time: 2.0567,
1329                    pressure: 1.0
1330                }
1331            ]
1332        ));
1333
1334        time += delta_time;
1335        let res4 = engine.update(ModelerInput {
1336            event_type: ModelerInputEventType::Move,
1337            pos: (4.9, -3.2),
1338            time: time,
1339            pressure: 1.0,
1340        });
1341        assert!(res4.is_ok());
1342        assert!(compare_results(
1343            res4.unwrap(),
1344            vec![ModelerResult {
1345                pos: (4.9953, -3.0237),
1346                velocity: (-1.1603, -3.7004),
1347                acceleration: (-274.4622, -380.4507),
1348                time: 2.0100,
1349                pressure: 1.0
1350            }]
1351        ));
1352
1353        assert!(engine.predict().is_ok());
1354        assert!(compare_results(
1355            engine.predict().unwrap(),
1356            vec![
1357                ModelerResult {
1358                    pos: (4.9828, -3.0521),
1359                    velocity: (-2.2559, -5.1049),
1360                    acceleration: (-197.1994, -252.8115),
1361                    time: 2.0156,
1362                    pressure: 1.0
1363                },
1364                ModelerResult {
1365                    pos: (4.9677, -3.0825),
1366                    velocity: (-2.7081, -5.4835),
1367                    acceleration: (-81.4051, -68.1520),
1368                    time: 2.0211,
1369                    pressure: 1.0
1370                },
1371                ModelerResult {
1372                    pos: (4.9526, -3.1115),
1373                    velocity: (-2.7333, -5.2122),
1374                    acceleration: (-4.5282, 48.8396),
1375                    time: 2.0267,
1376                    pressure: 1.0
1377                },
1378                ModelerResult {
1379                    pos: (4.9387, -3.1369),
1380                    velocity: (-2.4999, -4.5756),
1381                    acceleration: (42.0094, 114.5943),
1382                    time: 2.0322,
1383                    pressure: 1.0
1384                },
1385                ModelerResult {
1386                    pos: (4.9268, -3.1579),
1387                    velocity: (-2.1326, -3.7776),
1388                    acceleration: (66.1132, 143.6292),
1389                    time: 2.0378,
1390                    pressure: 1.0
1391                },
1392                ModelerResult {
1393                    pos: (4.9173, -3.1743),
1394                    velocity: (-1.7184, -2.9554),
1395                    acceleration: (74.5656, 147.9932),
1396                    time: 2.0433,
1397                    pressure: 1.0
1398                },
1399                ModelerResult {
1400                    pos: (4.9100, -3.1865),
1401                    velocity: (-1.3136, -2.1935),
1402                    acceleration: (72.8575, 137.1578),
1403                    time: 2.0489,
1404                    pressure: 1.0
1405                },
1406                ModelerResult {
1407                    pos: (4.9047, -3.1950),
1408                    velocity: (-0.9513, -1.5369),
1409                    acceleration: (65.2090, 118.1874),
1410                    time: 2.0544,
1411                    pressure: 1.0
1412                },
1413                ModelerResult {
1414                    pos: (4.9011, -3.2006),
1415                    velocity: (-0.6475, -1.0032),
1416                    acceleration: (54.6929, 96.0608),
1417                    time: 2.0600,
1418                    pressure: 1.0
1419                }
1420            ]
1421        ));
1422
1423        time += delta_time;
1424        let res5 = engine.update(ModelerInput {
1425            event_type: ModelerInputEventType::Move,
1426            pos: (4.825, -3.2),
1427            time: time,
1428            pressure: 1.0,
1429        });
1430
1431        assert!(res5.is_ok());
1432        assert!(compare_results(
1433            res5.unwrap(),
1434            vec![ModelerResult {
1435                pos: (4.9868, -3.0389),
1436                velocity: (-2.5540, -4.5431),
1437                acceleration: (-418.1093, -252.8115),
1438                time: 2.0133,
1439                pressure: 1.0,
1440            }]
1441        ));
1442
1443        assert!(engine.predict().is_ok());
1444        assert!(compare_results(
1445            engine.predict().unwrap(),
1446            vec![
1447                ModelerResult {
1448                    pos: (4.9636, -3.0687),
1449                    velocity: (-4.1801, -5.3627),
1450                    acceleration: (-292.6871, -147.5319),
1451                    time: 2.0189,
1452                    pressure: 1.0
1453                },
1454                ModelerResult {
1455                    pos: (4.9370, -3.0985),
1456                    velocity: (-4.7757, -5.3670),
1457                    acceleration: (-107.2116, -0.7651),
1458                    time: 2.0244,
1459                    pressure: 1.0
1460                },
1461                ModelerResult {
1462                    pos: (4.9109, -3.1256),
1463                    velocity: (-4.6989, -4.8816),
1464                    acceleration: (13.8210, 87.3644),
1465                    time: 2.0300,
1466                    pressure: 1.0
1467                },
1468                ModelerResult {
1469                    pos: (4.8875, -3.1486),
1470                    velocity: (-4.2257, -4.1466),
1471                    acceleration: (85.1835, 132.2997),
1472                    time: 2.0356,
1473                    pressure: 1.0
1474                },
1475                ModelerResult {
1476                    pos: (4.8677, -3.1671),
1477                    velocity: (-3.5576, -3.3287),
1478                    acceleration: (120.2579, 147.2335),
1479                    time: 2.0411,
1480                    pressure: 1.0
1481                },
1482                ModelerResult {
1483                    pos: (4.8520, -3.1812),
1484                    velocity: (-2.8333, -2.5353),
1485                    acceleration: (130.3700, 142.8088),
1486                    time: 2.0467,
1487                    pressure: 1.0
1488                },
1489                ModelerResult {
1490                    pos: (4.8401, -3.1914),
1491                    velocity: (-2.1411, -1.8288),
1492                    acceleration: (124.5846, 127.1714),
1493                    time: 2.0522,
1494                    pressure: 1.0
1495                },
1496                ModelerResult {
1497                    pos: (4.8316, -3.1982),
1498                    velocity: (-1.5312, -1.2386),
1499                    acceleration: (109.7874, 106.2279),
1500                    time: 2.0578,
1501                    pressure: 1.0
1502                },
1503                ModelerResult {
1504                    pos: (4.8280, -3.2010),
1505                    velocity: (-1.2786, -1.0053),
1506                    acceleration: (90.9288, 84.0051),
1507                    time: 2.0606,
1508                    pressure: 1.0
1509                },
1510                ModelerResult {
1511                    pos: (4.8272, -3.2017),
1512                    velocity: (-1.2209, -0.9529),
1513                    acceleration: (83.2052, 75.4288),
1514                    time: 2.0613,
1515                    pressure: 1.0
1516                }
1517            ]
1518        ));
1519
1520        time += delta_time;
1521        let res6 = engine.update(ModelerInput {
1522            event_type: ModelerInputEventType::Move,
1523            pos: (4.75, -3.225),
1524            time: time,
1525            pressure: 1.0,
1526        });
1527        assert!(res6.is_ok());
1528        assert!(compare_results(
1529            res6.unwrap(),
1530            vec![ModelerResult {
1531                pos: (4.9726, -3.0565),
1532                velocity: (-4.2660, -5.2803),
1533                acceleration: (-513.5957, -221.1678),
1534                time: 2.0167,
1535                pressure: 1.0
1536            }]
1537        ));
1538
1539        assert!(engine.predict().is_ok());
1540        assert!(compare_results(
1541            engine.predict().unwrap(),
1542            vec![
1543                ModelerResult {
1544                    pos: (4.9381, -3.0894),
1545                    velocity: (-6.2018, -5.9261),
1546                    acceleration: (-348.4476, -116.2445),
1547                    time: 2.0222,
1548                    pressure: 1.0
1549                },
1550                ModelerResult {
1551                    pos: (4.9004, -3.1215),
1552                    velocity: (-6.7995, -5.7749),
1553                    acceleration: (-107.5834, 27.2264),
1554                    time: 2.0278,
1555                    pressure: 1.0
1556                },
1557                ModelerResult {
1558                    pos: (4.8640, -3.1501),
1559                    velocity: (-6.5400, -5.1591),
1560                    acceleration: (46.7146, 110.8336),
1561                    time: 2.0333,
1562                    pressure: 1.0
1563                },
1564                ModelerResult {
1565                    pos: (4.8319, -3.1741),
1566                    velocity: (-5.7897, -4.3207),
1567                    acceleration: (135.0462, 150.9226),
1568                    time: 2.0389,
1569                    pressure: 1.0
1570                },
1571                ModelerResult {
1572                    pos: (4.8051, -3.1932),
1573                    velocity: (-4.8132, -3.4248),
1574                    acceleration: (175.7684, 161.2555),
1575                    time: 2.0444,
1576                    pressure: 1.0
1577                },
1578                ModelerResult {
1579                    pos: (4.7841, -3.2075),
1580                    velocity: (-3.7898, -2.5759),
1581                    acceleration: (184.2227, 152.7958),
1582                    time: 2.0500,
1583                    pressure: 1.0
1584                },
1585                ModelerResult {
1586                    pos: (4.7683, -3.2176),
1587                    velocity: (-2.8312, -1.8324),
1588                    acceleration: (172.5480, 133.8294),
1589                    time: 2.0556,
1590                    pressure: 1.0
1591                },
1592                ModelerResult {
1593                    pos: (4.7572, -3.2244),
1594                    velocity: (-1.9986, -1.2198),
1595                    acceleration: (149.8577, 110.2830),
1596                    time: 2.0611,
1597                    pressure: 1.0
1598                },
1599                ModelerResult {
1600                    pos: (4.7526, -3.2271),
1601                    velocity: (-1.6580, -0.9805),
1602                    acceleration: (122.6198, 86.1299),
1603                    time: 2.0639,
1604                    pressure: 1.0
1605                }
1606            ]
1607        ));
1608
1609        time += delta_time;
1610        let res7 = engine.update(ModelerInput {
1611            event_type: ModelerInputEventType::Move,
1612            pos: (4.7, -3.3),
1613            time: time,
1614            pressure: 1.0,
1615        });
1616        assert!(res7.is_ok());
1617        assert!(compare_results(
1618            res7.unwrap(),
1619            vec![ModelerResult {
1620                pos: (4.9529, -3.0778),
1621                velocity: (-5.9184, -6.4042),
1622                acceleration: (-495.7209, -337.1538),
1623                time: 2.0200,
1624                pressure: 1.0
1625            }]
1626        ));
1627        assert!(engine.predict().is_ok());
1628        assert!(compare_results(
1629            engine.predict().unwrap(),
1630            vec![
1631                ModelerResult {
1632                    pos: (4.9101, -3.1194),
1633                    velocity: (-7.6886, -7.4784),
1634                    acceleration: (-318.6394, -193.3594),
1635                    time: 2.0256,
1636                    pressure: 1.0
1637                },
1638                ModelerResult {
1639                    pos: (4.8654, -3.1607),
1640                    velocity: (-8.0518, -7.4431),
1641                    acceleration: (-65.3698, 6.3579),
1642                    time: 2.0311,
1643                    pressure: 1.0
1644                },
1645                ModelerResult {
1646                    pos: (4.8235, -3.1982),
1647                    velocity: (-7.5377, -6.7452),
1648                    acceleration: (92.5345, 125.6104),
1649                    time: 2.0367,
1650                    pressure: 1.0
1651                },
1652                ModelerResult {
1653                    pos: (4.7872, -3.2299),
1654                    velocity: (-6.5440, -5.7133),
1655                    acceleration: (178.8654, 185.7426),
1656                    time: 2.0422,
1657                    pressure: 1.0
1658                },
1659                ModelerResult {
1660                    pos: (4.7574, -3.2553),
1661                    velocity: (-5.3529, -4.5748),
1662                    acceleration: (214.4027, 204.9362),
1663                    time: 2.0478,
1664                    pressure: 1.0
1665                },
1666                ModelerResult {
1667                    pos: (4.7344, -3.2746),
1668                    velocity: (-4.1516, -3.4758),
1669                    acceleration: (216.2348, 197.8224),
1670                    time: 2.0533,
1671                    pressure: 1.0
1672                },
1673                ModelerResult {
1674                    pos: (4.7174, -3.2885),
1675                    velocity: (-3.0534, -2.5004),
1676                    acceleration: (197.6767, 175.5702),
1677                    time: 2.0589,
1678                    pressure: 1.0
1679                },
1680                ModelerResult {
1681                    pos: (4.7056, -3.2979),
1682                    velocity: (-2.1169, -1.6879),
1683                    acceleration: (168.5711, 146.2573),
1684                    time: 2.0644,
1685                    pressure: 1.0
1686                },
1687                ModelerResult {
1688                    pos: (4.7030, -3.3000),
1689                    velocity: (-1.9283, -1.5276),
1690                    acceleration: (135.7820, 115.3739),
1691                    time: 2.0658,
1692                    pressure: 1.0
1693                },
1694                ModelerResult {
1695                    pos: (4.7017, -3.3010),
1696                    velocity: (-1.8380, -1.4512),
1697                    acceleration: (130.0928, 110.0859),
1698                    time: 2.0665,
1699                    pressure: 1.0
1700                },
1701            ]
1702        ));
1703
1704        time += delta_time;
1705        let res8 = engine.update(ModelerInput {
1706            event_type: ModelerInputEventType::Move,
1707            pos: (4.675, -3.4),
1708            time: time,
1709            pressure: 1.0,
1710        });
1711        assert!(res8.is_ok());
1712        assert!(compare_results(
1713            res8.unwrap(),
1714            vec![ModelerResult {
1715                pos: (4.9288, -3.1046),
1716                velocity: (-7.2260, -8.0305),
1717                acceleration: (-392.2747, -487.9053),
1718                time: 2.0233,
1719                pressure: 1.0
1720            },]
1721        ));
1722
1723        assert!(engine.predict().is_ok());
1724        assert!(compare_results(
1725            engine.predict().unwrap(),
1726            vec![
1727                ModelerResult {
1728                    pos: (4.8816, -3.1582),
1729                    velocity: (-8.4881, -9.6525),
1730                    acceleration: (-227.1831, -291.9628),
1731                    time: 2.0289,
1732                    pressure: 1.0
1733                },
1734                ModelerResult {
1735                    pos: (4.8345, -3.2124),
1736                    velocity: (-8.4738, -9.7482),
1737                    acceleration: (2.5870, -17.2266),
1738                    time: 2.0344,
1739                    pressure: 1.0
1740                },
1741                ModelerResult {
1742                    pos: (4.7918, -3.2619),
1743                    velocity: (-7.6948, -8.9195),
1744                    acceleration: (140.2131, 149.1810),
1745                    time: 2.0400,
1746                    pressure: 1.0
1747                },
1748                ModelerResult {
1749                    pos: (4.7555, -3.3042),
1750                    velocity: (-6.5279, -7.6113),
1751                    acceleration: (210.0428, 235.4638),
1752                    time: 2.0456,
1753                    pressure: 1.0
1754                },
1755                ModelerResult {
1756                    pos: (4.7264, -3.3383),
1757                    velocity: (-5.2343, -6.1345),
1758                    acceleration: (232.8451, 265.8274),
1759                    time: 2.0511,
1760                    pressure: 1.0
1761                },
1762                ModelerResult {
1763                    pos: (4.7043, -3.3643),
1764                    velocity: (-3.9823, -4.6907),
1765                    acceleration: (225.3593, 259.8790),
1766                    time: 2.0567,
1767                    pressure: 1.0
1768                },
1769                ModelerResult {
1770                    pos: (4.6884, -3.3832),
1771                    velocity: (-2.8691, -3.3980),
1772                    acceleration: (200.3802, 232.6849),
1773                    time: 2.0622,
1774                    pressure: 1.0
1775                },
1776                ModelerResult {
1777                    pos: (4.6776, -3.3961),
1778                    velocity: (-1.9403, -2.3135),
1779                    acceleration: (167.1764, 195.2152),
1780                    time: 2.0678,
1781                    pressure: 1.0
1782                },
1783                ModelerResult {
1784                    pos: (4.6752, -3.3990),
1785                    velocity: (-1.7569, -2.0983),
1786                    acceleration: (132.0560, 154.9868),
1787                    time: 2.0692,
1788                    pressure: 1.0
1789                },
1790            ]
1791        ));
1792        time += delta_time;
1793
1794        let res9 = engine.update(ModelerInput {
1795            event_type: ModelerInputEventType::Move,
1796            pos: (4.675, -3.525),
1797            time: time,
1798            pressure: 1.0,
1799        });
1800        assert!(res9.is_ok());
1801        assert!(compare_results(
1802            res9.unwrap(),
1803            vec![ModelerResult {
1804                pos: (4.9022, -3.1387),
1805                velocity: (-7.9833, -10.2310),
1806                acceleration: (-227.1831, -660.1446),
1807                time: 2.0267,
1808                pressure: 1.0
1809            },]
1810        ));
1811
1812        assert!(engine.predict().is_ok());
1813        assert!(compare_results(
1814            engine.predict().unwrap(),
1815            vec![
1816                ModelerResult {
1817                    pos: (4.8549, -3.2079),
1818                    velocity: (-8.5070, -12.4602),
1819                    acceleration: (-94.2781, -401.2599),
1820                    time: 2.0322,
1821                    pressure: 1.0
1822                },
1823                ModelerResult {
1824                    pos: (4.8102, -3.2783),
1825                    velocity: (-8.0479, -12.6650),
1826                    acceleration: (82.6390, -36.8616),
1827                    time: 2.0378,
1828                    pressure: 1.0
1829                },
1830                ModelerResult {
1831                    pos: (4.7711, -3.3429),
1832                    velocity: (-7.0408, -11.6365),
1833                    acceleration: (181.2765, 185.1286),
1834                    time: 2.0433,
1835                    pressure: 1.0
1836                },
1837                ModelerResult {
1838                    pos: (4.7389, -3.3983),
1839                    velocity: (-5.7965, -9.9616),
1840                    acceleration: (223.9801, 301.4933),
1841                    time: 2.0489,
1842                    pressure: 1.0
1843                },
1844                ModelerResult {
1845                    pos: (4.7137, -3.4430),
1846                    velocity: (-4.5230, -8.0510),
1847                    acceleration: (229.2397, 343.9032),
1848                    time: 2.0544,
1849                    pressure: 1.0
1850                },
1851                ModelerResult {
1852                    pos: (4.6951, -3.4773),
1853                    velocity: (-3.3477, -6.1727),
1854                    acceleration: (211.5554, 338.0856),
1855                    time: 2.0600,
1856                    pressure: 1.0
1857                },
1858                ModelerResult {
1859                    pos: (4.6821, -3.5022),
1860                    velocity: (-2.3381, -4.4846),
1861                    acceleration: (181.7131, 303.8597),
1862                    time: 2.0656,
1863                    pressure: 1.0
1864                },
1865                ModelerResult {
1866                    pos: (4.6737, -3.5192),
1867                    velocity: (-1.5199, -3.0641),
1868                    acceleration: (147.2879, 255.7003),
1869                    time: 2.0711,
1870                    pressure: 1.0
1871                },
1872                ModelerResult {
1873                    pos: (4.6718, -3.5231),
1874                    velocity: (-1.3626, -2.7813),
1875                    acceleration: (113.2437, 203.5595),
1876                    time: 2.0725,
1877                    pressure: 1.0
1878                },
1879            ]
1880        ));
1881
1882        time += delta_time;
1883        // we get more results at the end of the stroke (stroke end catch up)
1884        let res10 = engine.update(ModelerInput {
1885            event_type: ModelerInputEventType::Up,
1886            pos: (4.7, -3.6),
1887            time: time,
1888            pressure: 1.0,
1889        });
1890        assert!(res10.is_ok());
1891        assert!(compare_results(
1892            res10.unwrap(),
1893            vec![
1894                ModelerResult {
1895                    pos: (4.8753, -3.1797),
1896                    velocity: (-8.0521, -12.3049),
1897                    acceleration: (-20.6429, -622.1685),
1898                    time: 2.0300,
1899                    pressure: 1.0
1900                },
1901                ModelerResult {
1902                    pos: (4.8325, -3.2589),
1903                    velocity: (-7.7000, -14.2607),
1904                    acceleration: (63.3680, -352.0363),
1905                    time: 2.0356,
1906                    pressure: 1.0
1907                },
1908                ModelerResult {
1909                    pos: (4.7948, -3.3375),
1910                    velocity: (-6.7888, -14.1377),
1911                    acceleration: (164.0215, 22.1350),
1912                    time: 2.0411,
1913                    pressure: 1.0
1914                },
1915                ModelerResult {
1916                    pos: (4.7636, -3.4085),
1917                    velocity: (-5.6249, -12.7787),
1918                    acceleration: (209.5020, 244.6249),
1919                    time: 2.0467,
1920                    pressure: 1.0
1921                },
1922                ModelerResult {
1923                    pos: (4.7390, -3.4685),
1924                    velocity: (-4.4152, -10.8015),
1925                    acceleration: (217.7452, 355.8801),
1926                    time: 2.0522,
1927                    pressure: 1.0
1928                },
1929                ModelerResult {
1930                    pos: (4.7208, -3.5164),
1931                    velocity: (-3.2880, -8.6333),
1932                    acceleration: (202.8961, 390.2804),
1933                    time: 2.0578,
1934                    pressure: 1.0
1935                },
1936                ModelerResult {
1937                    pos: (4.7079, -3.5528),
1938                    velocity: (-2.3128, -6.5475),
1939                    acceleration: (175.5414, 375.4407),
1940                    time: 2.0633,
1941                    pressure: 1.0
1942                },
1943                ModelerResult {
1944                    pos: (4.6995, -3.5789),
1945                    velocity: (-1.5174, -4.7008),
1946                    acceleration: (143.1705, 332.4062),
1947                    time: 2.0689,
1948                    pressure: 1.0
1949                },
1950                ModelerResult {
1951                    pos: (4.6945, -3.5965),
1952                    velocity: (-0.9022, -3.1655),
1953                    acceleration: (110.7325, 276.3669),
1954                    time: 2.0744,
1955                    pressure: 1.0
1956                },
1957                ModelerResult {
1958                    pos: (4.6942, -3.5976),
1959                    velocity: (-0.8740, -3.0899),
1960                    acceleration: (81.2036, 217.6189),
1961                    time: 2.0748,
1962                    pressure: 1.0
1963                },
1964            ]
1965        ));
1966
1967        // the stroke is finished so there's nothing left to predict
1968        assert!(engine.predict().is_err());
1969    }
1970
1971    #[test]
1972    fn wobble_smoothed() {
1973        let delta_time = 0.0167;
1974        let mut engine = StrokeModeler::default();
1975
1976        let mut time = 4.0;
1977        let res1 = engine.update(ModelerInput {
1978            event_type: ModelerInputEventType::Down,
1979            pos: (-6.0, -2.0),
1980            time: time,
1981            pressure: 1.0,
1982        });
1983        assert!(res1.is_ok());
1984        assert!(compare_results(
1985            res1.unwrap(),
1986            vec![ModelerResult {
1987                pos: (-6.0, -2.0),
1988                time: 4.0,
1989                ..ModelerResult::default()
1990            }]
1991        ));
1992
1993        time += delta_time;
1994
1995        let res2 = engine.update(ModelerInput {
1996            event_type: ModelerInputEventType::Move,
1997            pos: (-6.02, -2.0),
1998            time: time,
1999            ..ModelerInput::default()
2000        });
2001        assert!(res2.is_ok());
2002        assert!(compare_results(
2003            res2.unwrap(),
2004            vec![
2005                ModelerResult {
2006                    pos: (-6.0003, -2.0),
2007                    velocity: (-0.0615, 0.0),
2008                    acceleration: (-14.7276, 0.0),
2009                    time: 4.0042,
2010                    pressure: 1.0
2011                },
2012                ModelerResult {
2013                    pos: (-6.0009, -2.0),
2014                    velocity: (-0.1628, 0.0),
2015                    acceleration: (-24.2725, 0.0),
2016                    time: 4.0084,
2017                    pressure: 1.0
2018                },
2019                ModelerResult {
2020                    pos: (-6.0021, -2.0),
2021                    velocity: (-0.2868, 0.0),
2022                    acceleration: (-29.6996, 0.0),
2023                    time: 4.0125,
2024                    pressure: 1.0
2025                },
2026                ModelerResult {
2027                    pos: (-6.0039, -2.0),
2028                    velocity: (-0.4203, 0.0),
2029                    acceleration: (-31.9728, 0.0),
2030                    time: 4.0167,
2031                    pressure: 1.0
2032                },
2033            ]
2034        ));
2035
2036        time += delta_time;
2037        let res3 = engine.update(ModelerInput {
2038            event_type: ModelerInputEventType::Move,
2039            pos: (-6.02, -2.02),
2040            time: time,
2041            pressure: 1.0,
2042        });
2043        assert!(res3.is_ok());
2044        assert!(compare_results(
2045            res3.unwrap(),
2046            vec![
2047                ModelerResult {
2048                    pos: (-6.0059, -2.0001),
2049                    velocity: (-0.4921, -0.0307),
2050                    acceleration: (-17.1932, -7.3638),
2051                    time: 4.0209,
2052                    pressure: 1.0
2053                },
2054                ModelerResult {
2055                    pos: (-6.0081, -2.0005),
2056                    velocity: (-0.5170, -0.0814),
2057                    acceleration: (-5.9729, -12.1355),
2058                    time: 4.0251,
2059                    pressure: 1.0
2060                },
2061                ModelerResult {
2062                    pos: (-6.0102, -2.0010),
2063                    velocity: (-0.5079, -0.1434),
2064                    acceleration: (2.1807, -14.8493),
2065                    time: 4.0292,
2066                    pressure: 1.0
2067                },
2068                ModelerResult {
2069                    pos: (-6.0122, -2.0019),
2070                    velocity: (-0.4755, -0.2101),
2071                    acceleration: (7.7710, -15.9860),
2072                    time: 4.0334,
2073                    pressure: 1.0
2074                },
2075            ]
2076        ));
2077        time += delta_time;
2078        let res4 = engine.update(ModelerInput {
2079            event_type: ModelerInputEventType::Move,
2080            pos: (-6.04, -2.02),
2081            time: time,
2082            pressure: 1.0,
2083        });
2084        assert!(res4.is_ok());
2085        assert!(compare_results(
2086            res4.unwrap(),
2087            vec![
2088                ModelerResult {
2089                    pos: (-6.0141, -2.0030),
2090                    velocity: (-0.4489, -0.2563),
2091                    acceleration: (6.3733, -11.0507),
2092                    time: 4.0376,
2093                    pressure: 1.0
2094                },
2095                ModelerResult {
2096                    pos: (-6.0159, -2.0042),
2097                    velocity: (-0.4277, -0.2856),
2098                    acceleration: (5.0670, -7.0315),
2099                    time: 4.0418,
2100                    pressure: 1.0
2101                },
2102                ModelerResult {
2103                    pos: (-6.0176, -2.0055),
2104                    velocity: (-0.4115, -0.3018),
2105                    acceleration: (3.8950, -3.8603),
2106                    time: 4.0459,
2107                    pressure: 1.0
2108                },
2109                ModelerResult {
2110                    pos: (-6.0193, -2.0067),
2111                    velocity: (-0.3994, -0.3078),
2112                    acceleration: (2.8758, -1.4435),
2113                    time: 4.0501,
2114                    pressure: 1.0
2115                },
2116            ]
2117        ));
2118
2119        time += delta_time;
2120        let res5 = engine.update(ModelerInput {
2121            event_type: ModelerInputEventType::Move,
2122            pos: (-6.04, -2.04),
2123            time: time,
2124            pressure: 1.0,
2125        });
2126        assert!(res5.is_ok());
2127        assert!(
2128            (compare_results(
2129                res5.unwrap(),
2130                vec![
2131                    ModelerResult {
2132                        pos: (-6.0209, -2.0082),
2133                        velocity: (-0.3910, -0.3372),
2134                        acceleration: (2.0142, -7.0427),
2135                        time: 4.0543,
2136                        pressure: 1.0
2137                    },
2138                    ModelerResult {
2139                        pos: (-6.0225, -2.0098),
2140                        velocity: (-0.3856, -0.3814),
2141                        acceleration: (1.3090, -10.5977),
2142                        time: 4.0585,
2143                        pressure: 1.0
2144                    },
2145                    ModelerResult {
2146                        pos: (-6.0241, -2.0116),
2147                        velocity: (-0.3825, -0.4338),
2148                        acceleration: (0.7470, -12.5399),
2149                        time: 4.0626,
2150                        pressure: 1.0
2151                    },
2152                    ModelerResult {
2153                        pos: (-6.0257, -2.0136),
2154                        velocity: (-0.3811, -0.4891),
2155                        acceleration: (0.3174, -13.2543),
2156                        time: 4.0668,
2157                        pressure: 1.0
2158                    },
2159                ]
2160            ))
2161        );
2162    }
2163
2164    #[test]
2165    fn reset_stroke() {
2166        let mut engine = StrokeModeler::default();
2167        let delta_time = 1. / 50.;
2168        let mut time = 0.0;
2169        let res = engine.update(ModelerInput {
2170            event_type: ModelerInputEventType::Down,
2171            pos: (-8.0, -10.0),
2172            time: time,
2173            pressure: 1.0,
2174        });
2175        assert!(res.is_ok());
2176        assert!(!res.unwrap().is_empty());
2177        assert!(engine.predict().is_ok());
2178        assert!(engine.predict().unwrap().is_empty());
2179
2180        time += delta_time;
2181        let res2 = engine.update(ModelerInput {
2182            event_type: ModelerInputEventType::Move,
2183            time: time,
2184            ..ModelerInput::default()
2185        });
2186        assert!(res2.is_ok());
2187        assert!(!res2.unwrap().is_empty());
2188        assert!(engine.predict().is_ok());
2189        assert!(!engine.predict().unwrap().is_empty());
2190
2191        time += delta_time;
2192        let res3 = engine.update(ModelerInput {
2193            event_type: ModelerInputEventType::Move,
2194            time: time,
2195            pos: (-11.0, -5.0),
2196            ..ModelerInput::default()
2197        });
2198        assert!(res3.is_ok());
2199        assert!(!res3.unwrap().is_empty());
2200        assert!(engine.predict().is_ok());
2201        assert!(!engine.predict().unwrap().is_empty());
2202
2203        engine.reset();
2204        assert!(engine.predict().is_err());
2205    }
2206
2207    #[test]
2208    fn ignore_input_before_down() {
2209        let mut engine = StrokeModeler::default();
2210
2211        assert!(
2212            engine
2213                .update(ModelerInput {
2214                    event_type: ModelerInputEventType::Move,
2215                    ..ModelerInput::default()
2216                })
2217                .is_err()
2218        );
2219        assert!(
2220            engine
2221                .update(ModelerInput {
2222                    event_type: ModelerInputEventType::Up,
2223                    ..ModelerInput::default()
2224                })
2225                .is_err()
2226        );
2227    }
2228
2229    #[test]
2230    fn tdown_in_progress_error() {
2231        let mut engine = StrokeModeler::default();
2232
2233        assert!(
2234            engine
2235                .update(ModelerInput {
2236                    event_type: ModelerInputEventType::Down,
2237                    ..ModelerInput::default()
2238                })
2239                .is_ok()
2240        );
2241        assert!(
2242            engine
2243                .update(ModelerInput {
2244                    event_type: ModelerInputEventType::Down,
2245                    ..ModelerInput::default()
2246                })
2247                .is_err()
2248        );
2249    }
2250
2251    #[test]
2252    fn alternate_params() {
2253        let delta_time = 1. / 50.;
2254        let mut engine = StrokeModeler::new(ModelerParams {
2255            sampling_min_output_rate: 70.0,
2256            stylus_state_modeler_max_input_samples: 20,
2257            ..ModelerParams::suggested()
2258        })
2259        .unwrap();
2260
2261        let mut time = 3.0;
2262
2263        let res1 = engine.update(ModelerInput {
2264            event_type: ModelerInputEventType::Down,
2265            pos: (0.0, 0.0),
2266            time: time,
2267            pressure: 0.5,
2268        });
2269        assert!(res1.is_ok());
2270        assert!(compare_results(
2271            res1.unwrap(),
2272            vec![ModelerResult {
2273                time: 3.0,
2274                pressure: 0.5,
2275                ..ModelerResult::default()
2276            }]
2277        ));
2278
2279        assert!(engine.predict().is_ok());
2280        assert!(engine.predict().unwrap().is_empty());
2281
2282        time += delta_time;
2283
2284        let res2 = engine.update(ModelerInput {
2285            event_type: ModelerInputEventType::Move,
2286            pos: (0.0, 0.5),
2287            time: time,
2288            pressure: 0.4,
2289        });
2290        assert!(res2.is_ok());
2291        assert!(compare_results(
2292            res2.unwrap(),
2293            vec![
2294                ModelerResult {
2295                    pos: (0.0, 0.0736),
2296                    velocity: (0.0, 7.3636),
2297                    acceleration: (0.0, 736.3636),
2298                    time: 3.0100,
2299                    pressure: 0.4853
2300                },
2301                ModelerResult {
2302                    pos: (0.0, 0.2198),
2303                    velocity: (0.0, 14.6202),
2304                    acceleration: (0.0, 725.6529),
2305                    time: 3.0200,
2306                    pressure: 0.4560
2307                },
2308            ]
2309        ));
2310
2311        assert!(engine.predict().is_ok());
2312        assert!(compare_results(
2313            engine.predict().unwrap(),
2314            vec![
2315                ModelerResult {
2316                    pos: (0.0, 0.3823),
2317                    velocity: (0.0, 11.3709),
2318                    acceleration: (0.0, -227.4474),
2319                    time: 3.0343,
2320                    pressure: 0.4235
2321                },
2322                ModelerResult {
2323                    pos: (0.0, 0.4484),
2324                    velocity: (0.0, 4.6285),
2325                    acceleration: (0.0, -471.9660),
2326                    time: 3.0486,
2327                    pressure: 0.4103
2328                },
2329                ModelerResult {
2330                    pos: (0.0, 0.4775),
2331                    velocity: (0.0, 2.0389),
2332                    acceleration: (0.0, -181.2747),
2333                    time: 3.0629,
2334                    pressure: 0.4045
2335                },
2336                ModelerResult {
2337                    pos: (0.0, 0.4902),
2338                    velocity: (0.0, 0.8873),
2339                    acceleration: (0.0, -80.6136),
2340                    time: 3.0771,
2341                    pressure: 0.4020
2342                },
2343                ModelerResult {
2344                    pos: (0.0, 0.4957),
2345                    velocity: (0.0, 0.3868),
2346                    acceleration: (0.0, -35.0318),
2347                    time: 3.0914,
2348                    pressure: 0.4009
2349                },
2350                ModelerResult {
2351                    pos: (0.0, 0.4981),
2352                    velocity: (0.0, 0.1686),
2353                    acceleration: (0.0, -15.2760),
2354                    time: 3.1057,
2355                    pressure: 0.4004
2356                },
2357                ModelerResult {
2358                    pos: (0.0, 0.4992),
2359                    velocity: (0.0, 0.0735),
2360                    acceleration: (0.0, -6.6579),
2361                    time: 3.1200,
2362                    pressure: 0.4002
2363                },
2364            ]
2365        ));
2366        time += delta_time;
2367
2368        let res3 = engine.update(ModelerInput {
2369            pos: (0.2, 1.0),
2370            time: time,
2371            pressure: 0.3,
2372            event_type: ModelerInputEventType::Move,
2373        });
2374        assert!(res3.is_ok());
2375        assert!(compare_results(
2376            res3.unwrap(),
2377            vec![
2378                ModelerResult {
2379                    pos: (0.0295, 0.4169),
2380                    velocity: (2.9455, 19.7093),
2381                    acceleration: (294.5455, 508.9161),
2382                    time: 3.0300,
2383                    pressure: 0.4166
2384                },
2385                ModelerResult {
2386                    pos: (0.0879, 0.6439),
2387                    velocity: (5.8481, 22.6926),
2388                    acceleration: (290.2612, 298.3311),
2389                    time: 3.0400,
2390                    pressure: 0.3691
2391                },
2392            ]
2393        ));
2394
2395        assert!(engine.predict().is_ok());
2396        assert!(compare_results(
2397            engine.predict().unwrap(),
2398            vec![
2399                ModelerResult {
2400                    pos: (0.1529, 0.8487),
2401                    velocity: (4.5484, 14.3374),
2402                    acceleration: (-90.9790, -584.8687),
2403                    time: 3.0543,
2404                    pressure: 0.3293
2405                },
2406                ModelerResult {
2407                    pos: (0.1794, 0.9338),
2408                    velocity: (1.8514, 5.9577),
2409                    acceleration: (-188.7864, -586.5760),
2410                    time: 3.0686,
2411                    pressure: 0.3128
2412                },
2413                ModelerResult {
2414                    pos: (0.1910, 0.9712),
2415                    velocity: (0.8156, 2.6159),
2416                    acceleration: (-72.5099, -233.9289),
2417                    time: 3.0829,
2418                    pressure: 0.3056
2419                },
2420                ModelerResult {
2421                    pos: (0.1961, 0.9874),
2422                    velocity: (0.3549, 1.1389),
2423                    acceleration: (-32.2455, -103.3868),
2424                    time: 3.0971,
2425                    pressure: 0.3024
2426                },
2427                ModelerResult {
2428                    pos: (0.1983, 0.9945),
2429                    velocity: (0.1547, 0.4965),
2430                    acceleration: (-14.0127, -44.9693),
2431                    time: 3.1114,
2432                    pressure: 0.3011
2433                },
2434                ModelerResult {
2435                    pos: (0.1993, 0.9976),
2436                    velocity: (0.0674, 0.2164),
2437                    acceleration: (-6.1104, -19.6068),
2438                    time: 3.1257,
2439                    pressure: 0.3005
2440                },
2441                ModelerResult {
2442                    pos: (0.1997, 0.9990),
2443                    velocity: (0.0294, 0.0943),
2444                    acceleration: (-2.6631, -8.5455),
2445                    time: 3.1400,
2446                    pressure: 0.3002
2447                },
2448            ]
2449        ));
2450
2451        time += delta_time;
2452        let res4 = engine.update(ModelerInput {
2453            event_type: ModelerInputEventType::Move,
2454            pos: (0.4, 1.4),
2455            time: time,
2456            pressure: 0.2,
2457        });
2458        assert!(res4.is_ok());
2459        assert!(compare_results(
2460            res4.unwrap(),
2461            vec![
2462                ModelerResult {
2463                    pos: (0.1668, 0.8712),
2464                    velocity: (7.8837, 22.7349),
2465                    acceleration: (203.5665, 4.2224),
2466                    time: 3.0500,
2467                    pressure: 0.3245
2468                },
2469                ModelerResult {
2470                    pos: (0.2575, 1.0906),
2471                    velocity: (9.0771, 21.9411),
2472                    acceleration: (119.3324, -79.3721),
2473                    time: 3.0600,
2474                    pressure: 0.2761
2475                },
2476            ]
2477        ));
2478        assert!(engine.predict().is_ok());
2479        assert!(compare_results(
2480            engine.predict().unwrap(),
2481            vec![
2482                ModelerResult {
2483                    pos: (0.3395, 1.2676),
2484                    velocity: (5.7349, 12.3913),
2485                    acceleration: (-233.9475, -668.4906),
2486                    time: 3.0743,
2487                    pressure: 0.2325
2488                },
2489                ModelerResult {
2490                    pos: (0.3735, 1.3421),
2491                    velocity: (2.3831, 5.2156),
2492                    acceleration: (-234.6304, -502.2992),
2493                    time: 3.0886,
2494                    pressure: 0.2142
2495                },
2496                ModelerResult {
2497                    pos: (0.3885, 1.3748),
2498                    velocity: (1.0463, 2.2854),
2499                    acceleration: (-93.5716, -205.1091),
2500                    time: 3.1029,
2501                    pressure: 0.2062
2502                },
2503                ModelerResult {
2504                    pos: (0.3950, 1.3890),
2505                    velocity: (0.4556, 0.9954),
2506                    acceleration: (-41.3547, -90.3064),
2507                    time: 3.1171,
2508                    pressure: 0.2027
2509                },
2510                ModelerResult {
2511                    pos: (0.3978, 1.3952),
2512                    velocity: (0.1986, 0.4339),
2513                    acceleration: (-17.9877, -39.3021),
2514                    time: 3.1314,
2515                    pressure: 0.2012
2516                },
2517                ModelerResult {
2518                    pos: (0.3990, 1.3979),
2519                    velocity: (0.0866, 0.1891),
2520                    acceleration: (-7.8428, -17.1346),
2521                    time: 3.1457,
2522                    pressure: 0.2005
2523                },
2524                ModelerResult {
2525                    pos: (0.3996, 1.3991),
2526                    velocity: (0.0377, 0.0824),
2527                    acceleration: (-3.4182, -7.4680),
2528                    time: 3.1600,
2529                    pressure: 0.2002
2530                },
2531            ]
2532        ));
2533        time += delta_time;
2534        let res5 = engine.update(ModelerInput {
2535            event_type: ModelerInputEventType::Up,
2536            pos: (0.7, 1.7),
2537            pressure: 0.1,
2538            time: time,
2539        });
2540        assert!(res5.is_ok());
2541        assert!(compare_results(
2542            res5.unwrap(),
2543            vec![
2544                ModelerResult {
2545                    pos: (0.3691, 1.2874),
2546                    velocity: (11.1558, 19.6744),
2547                    acceleration: (207.8707, -226.6725),
2548                    time: 3.0700,
2549                    pressure: 0.2256
2550                },
2551                ModelerResult {
2552                    pos: (0.4978, 1.4640),
2553                    velocity: (12.8701, 17.6629),
2554                    acceleration: (171.4340, -201.1508),
2555                    time: 3.0800,
2556                    pressure: 0.1730
2557                },
2558                ModelerResult {
2559                    pos: (0.6141, 1.5986),
2560                    velocity: (8.1404, 9.4261),
2561                    acceleration: (-331.0815, -576.5752),
2562                    time: 3.0943,
2563                    pressure: 0.1312
2564                },
2565                ModelerResult {
2566                    pos: (0.6624, 1.6557),
2567                    velocity: (3.3822, 3.9953),
2568                    acceleration: (-333.0701, -380.1579),
2569                    time: 3.1086,
2570                    pressure: 0.1136
2571                },
2572                ModelerResult {
2573                    pos: (0.6836, 1.6807),
2574                    velocity: (1.4851, 1.7488),
2575                    acceleration: (-132.8005, -157.2520),
2576                    time: 3.1229,
2577                    pressure: 0.1059
2578                },
2579                ModelerResult {
2580                    pos: (0.6929, 1.6916),
2581                    velocity: (0.6466, 0.7618),
2582                    acceleration: (-58.6943, -69.0946),
2583                    time: 3.1371,
2584                    pressure: 0.1026
2585                },
2586                ModelerResult {
2587                    pos: (0.6969, 1.6963),
2588                    velocity: (0.2819, 0.3321),
2589                    acceleration: (-25.5298, -30.0794),
2590                    time: 3.1514,
2591                    pressure: 0.1011
2592                },
2593                ModelerResult {
2594                    pos: (0.6986, 1.6984),
2595                    velocity: (0.1229, 0.1447),
2596                    acceleration: (-11.1311, -13.1133),
2597                    time: 3.1657,
2598                    pressure: 0.1005
2599                },
2600                ModelerResult {
2601                    pos: (0.6994, 1.6993),
2602                    velocity: (0.0535, 0.0631),
2603                    acceleration: (-4.8514, -5.7153),
2604                    time: 3.1800,
2605                    pressure: 0.1002
2606                },
2607            ]
2608        ));
2609        assert!(engine.predict().is_err());
2610    }
2611
2612    #[test]
2613    fn generate_output_up_nodelta() {
2614        let delta_time = 1. / 500.;
2615        let mut engine = StrokeModeler::default();
2616        let mut time = 0.0;
2617
2618        let res1 = engine.update(ModelerInput {
2619            event_type: ModelerInputEventType::Down,
2620            pos: (5.0, 5.0),
2621            time: time,
2622            pressure: 1.0,
2623        });
2624        assert!(res1.is_ok());
2625        assert!(compare_results(
2626            res1.unwrap(),
2627            vec![ModelerResult {
2628                pos: (5.0, 5.0),
2629                time: 0.0,
2630                ..ModelerResult::default()
2631            }]
2632        ));
2633        time += delta_time;
2634        let res2 = engine.update(ModelerInput {
2635            event_type: ModelerInputEventType::Move,
2636            pos: (5.0, 5.0),
2637            pressure: 1.0,
2638            time: time,
2639        });
2640        assert!(res2.is_ok());
2641        assert!(compare_results(
2642            res2.unwrap(),
2643            vec![ModelerResult {
2644                pos: (5.0, 5.0),
2645                time: 0.002,
2646                ..ModelerResult::default()
2647            }]
2648        ));
2649        let res3 = engine.update(ModelerInput {
2650            event_type: ModelerInputEventType::Up,
2651            pos: (5.0, 5.0),
2652            time: time,
2653            pressure: 1.0,
2654        });
2655        assert!(res3.is_ok());
2656        assert!(compare_results(
2657            res3.unwrap(),
2658            vec![ModelerResult {
2659                pos: (5.0, 5.0),
2660                time: 0.0076,
2661                pressure: 1.0,
2662                ..ModelerResult::default()
2663            }]
2664        ));
2665    }
2666
2667    #[test]
2668    fn far_apart_times_move() {
2669        let mut engine = StrokeModeler::default();
2670        let res1 = engine.update(ModelerInput {
2671            event_type: ModelerInputEventType::Down,
2672            pos: (0.0, 0.0),
2673            time: 0.0,
2674            pressure: 0.2,
2675        });
2676        assert!(res1.is_ok());
2677        assert!(!res1.unwrap().is_empty());
2678
2679        let res2 = engine.update(ModelerInput {
2680            event_type: ModelerInputEventType::Move,
2681            pos: (0.0, 0.0),
2682            pressure: 0.2,
2683            time: 2147483647.0,
2684        });
2685        assert!(res2.is_err());
2686    }
2687
2688    #[test]
2689    fn far_apart_times_up() {
2690        let mut engine = StrokeModeler::default();
2691        let res1 = engine.update(ModelerInput {
2692            event_type: ModelerInputEventType::Down,
2693            pos: (0.0, 0.0),
2694            time: 0.0,
2695            pressure: 0.2,
2696        });
2697        assert!(res1.is_ok());
2698        assert!(!res1.unwrap().is_empty());
2699
2700        let res2 = engine.update(ModelerInput {
2701            event_type: ModelerInputEventType::Up,
2702            pos: (0.0, 0.0),
2703            pressure: 0.2,
2704            time: 2147483647.0,
2705        });
2706        assert!(res2.is_err());
2707    }
2708
2709    #[test]
2710    fn reject_negative_timedelta() {
2711        let mut engine = StrokeModeler::default();
2712        let res1 = engine.update(ModelerInput {
2713            event_type: ModelerInputEventType::Down,
2714            pos: (0.0, 0.0),
2715            time: 0.0,
2716            pressure: 0.0,
2717        });
2718        assert!(res1.is_ok());
2719        assert!(!res1.unwrap().is_empty());
2720
2721        let res2 = engine.update(ModelerInput {
2722            event_type: ModelerInputEventType::Move,
2723            pos: (1.0, 1.0),
2724            time: -0.1,
2725            pressure: 0.0,
2726        });
2727        assert!(res2.is_err());
2728
2729        let res3 = engine.update(ModelerInput {
2730            event_type: ModelerInputEventType::Move,
2731            pos: (1.0, 1.0),
2732            time: 0.1,
2733            pressure: 1.0,
2734        });
2735        assert!(res3.is_ok());
2736        assert!(!res3.unwrap().is_empty());
2737
2738        let res4 = engine.update(ModelerInput {
2739            event_type: ModelerInputEventType::Up,
2740            pos: (1.0, 1.0),
2741            time: 0.09,
2742            pressure: 1.0,
2743        });
2744        assert!(res4.is_err());
2745    }
2746
2747    #[test]
2748    fn reject_duplicate_input() {
2749        let mut engine = StrokeModeler::default();
2750        let res1 = engine.update(ModelerInput {
2751            event_type: ModelerInputEventType::Down,
2752            pos: (0.0, 0.0),
2753            time: 0.0,
2754            pressure: 0.2,
2755        });
2756        assert!(res1.is_ok());
2757        assert!(!res1.unwrap().is_empty());
2758
2759        let res2 = engine.update(ModelerInput {
2760            event_type: ModelerInputEventType::Down,
2761            pos: (0.0, 0.0),
2762            time: 0.0,
2763            pressure: 0.2,
2764        });
2765        assert!(res2.is_err());
2766
2767        let res3 = engine.update(ModelerInput {
2768            event_type: ModelerInputEventType::Move,
2769            pos: (1.0, 2.0),
2770            time: 0.1,
2771            pressure: 0.1,
2772        });
2773        assert!(res3.is_ok());
2774        assert!(!res3.unwrap().is_empty());
2775
2776        let res4 = engine.update(ModelerInput {
2777            event_type: ModelerInputEventType::Move,
2778            pos: (1.0, 2.0),
2779            time: 0.1,
2780            pressure: 0.1,
2781        });
2782        assert!(res4.is_err());
2783    }
2784}