multitouch 0.3.2

Raw macOS multitouch, gesture recognition, device monitoring, and Force Touch haptics
Documentation
use super::event::{
    GestureEndReason, GestureEvent, GesturePhase, MagnifyEvent, RotationEvent, SwipeEvent,
};
use super::recognizer::{GestureKind, GestureRecognizer};
use crate::Point;
use std::f32::consts::PI;
use std::time::Instant;

impl GestureRecognizer {
    pub(super) fn make_event(
        &self,
        phase: GesturePhase,
        centroid: Point,
        distance: f32,
        angle: f32,
        now: Instant,
        finger_count: usize,
    ) -> Option<GestureEvent> {
        let origin_centroid = self.origin_centroid?;
        let origin_distance = self.origin_distance?;
        let origin_angle = self.origin_angle?;
        let dt = self
            .last_event_time
            .map(|t| now.saturating_duration_since(t).as_secs_f32())
            .unwrap_or(0.0);

        match self.gesture_kind? {
            GestureKind::Swipe => {
                let translation = Point::new(
                    centroid.x - origin_centroid.x,
                    centroid.y - origin_centroid.y,
                );
                let velocity = if dt > 0.0 {
                    self.last_centroid
                        .map(|last| {
                            Point::new((centroid.x - last.x) / dt, (centroid.y - last.y) / dt)
                        })
                        .unwrap_or(Point::ZERO)
                } else {
                    Point::ZERO
                };
                Some(GestureEvent::Swipe(SwipeEvent {
                    phase,
                    translation,
                    velocity,
                    centroid,
                    angle: translation.y.atan2(translation.x),
                    distance: translation.x.hypot(translation.y),
                    finger_count,
                }))
            }
            GestureKind::Magnify => {
                let velocity = if dt > 0.0 {
                    self.last_distance
                        .map(|last| (distance - last) / dt)
                        .unwrap_or(0.0)
                } else {
                    0.0
                };
                Some(GestureEvent::Magnify(MagnifyEvent {
                    phase,
                    distance,
                    origin_distance,
                    velocity,
                    centroid,
                    finger_count,
                }))
            }
            GestureKind::Rotation => {
                let rotation = angle_difference(origin_angle, angle);
                let velocity = if dt > 0.0 {
                    self.last_angle
                        .map(|last| (rotation - angle_difference(origin_angle, last)) / dt)
                        .unwrap_or(0.0)
                } else {
                    0.0
                };
                Some(GestureEvent::Rotation(RotationEvent {
                    phase,
                    rotation,
                    velocity,
                    centroid,
                    finger_count,
                }))
            }
        }
    }

    pub(super) fn make_end_event(
        &self,
        reason: GestureEndReason,
        active_finger_count: usize,
        now: Instant,
    ) -> Option<GestureEvent> {
        self.make_event(
            GesturePhase::Ended(reason),
            self.last_centroid?,
            self.last_distance?,
            self.last_angle?,
            now,
            active_finger_count,
        )
    }
}

pub(super) fn angle_difference(a: f32, b: f32) -> f32 {
    let mut diff = b - a;
    while diff > PI {
        diff -= 2.0 * PI;
    }
    while diff < -PI {
        diff += 2.0 * PI;
    }
    diff
}