/// <summary> /// Gets inertial motion parameters: distance and duration. /// </summary> /// <param name="hostBounds">The host bounds.</param> /// <param name="windowBounds">The window bounds.</param> /// <returns> /// The inertial motion parameters: distance and duration. /// </returns> public InertialMotion GetInertialMotionParameters(Rect hostBounds, Rect windowBounds) { if (mouseTrails.Count < 2) return null; var mouseTrailsArray = mouseTrails.ToArray(); Point startPosition = mouseTrailsArray[0].Position; DateTime startTime = mouseTrailsArray[0].Timestamp; Point endPosition = mouseTrailsArray[mouseTrails.Count - 1].Position; DateTime endTime = mouseTrailsArray[mouseTrails.Count - 1].Timestamp; double timeBetweenNowAndLastMove = (DateTime.Now - endTime).TotalMilliseconds; Vector2 vector = new Vector2(startPosition, endPosition); if (timeBetweenNowAndLastMove < DELAY_BEFORE_MOUSE_UP_IN_MILLISECONDS && !vector.IsZero) { double time = (endTime - startTime).TotalSeconds; time = (time == 0) ? 0.001 : time; double distance = vector.Length / pixelsPerMeter; double intialVelocity = distance / time; double expectedDistance = ((intialVelocity * intialVelocity) / (2 * COEFFICIENT_OF_SLIDING_FRICTION * GRAVITATIONAL_ACCELERATION)); double expectedTime = (2 * expectedDistance) / intialVelocity; double shiftX = Math.Round(vector.LengthX * expectedDistance / distance); double shiftY = Math.Round(vector.LengthY * expectedDistance / distance); // New Inertial Motion Vector Vector2 imVector = new Vector2(endPosition, shiftX, shiftY).Round(); double expectedLength = imVector.Length; Rect bounds = hostBounds.Add(-windowBounds.Width, -windowBounds.Height); if (bounds.Contains(endPosition)) { imVector = EnsureEndPointInBounds(imVector, bounds).Round(); } else if (hostBounds.Contains(endPosition)) { imVector = EnsureEndPointInBounds(imVector, hostBounds).Round(); } // Reduce expected time if the Inertial Motion Vector was truncated by the bounds double realTime = (expectedLength == 0) ? 0 : (expectedTime * imVector.Length / expectedLength); var motion = new InertialMotion() { Seconds = realTime, EndPosition = imVector.End, EasingFunction = new CubicEase() { EasingMode = EasingMode.EaseOut } }; return motion; } return null; }