/// <summary>
        /// Gets the nearest point but allows for normalising the x and y
        /// by different distances, which is required if you scale the x
        /// and y seperately, but want to get the visually closest point.
        /// </summary>
        /// <param name="points"></param>
        /// <param name="point"></param>
        /// <param name="inverseNormalisation"></param>
        /// <param name="nearestDistanceSquared"></param>
        /// <returns></returns>
        public static PointAndPrimitive GetEllipseScaledNearestPoint(IEnumerable <PointAndPrimitive> points, Point point, Vector ratio, out double nearestDistanceSquared)
        {
            Point inverseNormalisation = new Point(1 / ratio.X, 1 / ratio.Y);

            nearestDistanceSquared = 0;

            PointAndPrimitive nearestPoint = new PointAndPrimitive(point, null);

            try {
                // Just pick off the first point to initialize stuff
                foreach (PointAndPrimitive testPoint in points)
                {
                    nearestDistanceSquared = new Vector((testPoint.X - point.X) * inverseNormalisation.X, (testPoint.Y - point.Y) * inverseNormalisation.Y).LengthSquared;
                    nearestPoint           = testPoint;
                    break;
                }

                // Loop through all points to find the closest
                foreach (PointAndPrimitive testPoint in points)
                {
                    double distanceSquared = new Vector((testPoint.X - point.X) * inverseNormalisation.X, (testPoint.Y - point.Y) * inverseNormalisation.Y).LengthSquared;
                    if (distanceSquared < nearestDistanceSquared)
                    {
                        nearestDistanceSquared = distanceSquared;
                        nearestPoint           = testPoint;
                    }
                }
            } catch (Exception) {
            }

            return(nearestPoint);
        }
        /// <summary>
        /// Handles when the mouse moves in a way that that it can execute on a thread that isn't
        /// the GUI thread.
        /// </summary>
        /// <param name="mousePos"></param>
        /// <param name="minimumBounds"></param>
        /// <returns></returns>
        public Point MouseMoved(Point mousePos, Rect minimumBounds)
        {
            bool newLocked             = false;
            PointAndPrimitive newPoint = new PointAndPrimitive(mousePos, null);

            lock (_points) {
                if (_points.Count > 0)
                {
                    double nearestDistanceSquared;
                    newPoint  = GetEllipseScaledNearestPoint(_points, mousePos, (Vector)(minimumBounds.Size), out nearestDistanceSquared);
                    newLocked = nearestDistanceSquared <= 1;
                }
            }

            bool lockedChanged = newLocked != _locked;
            bool pointChanged  = newPoint.Point != _closestPoint.Point;

            if (_closestPoint.Primitive != null && _closestPoint.Primitive.LegendLabel != null)
            {
                _closestPoint.Primitive.LegendLabel.IsHighlighted = false;
            }

            _locked       = newLocked;
            _closestPoint = newPoint;

            Action updateGui = () => {
                if (_closestPoint.Primitive != null)
                {
                    ChartPrimitive primitive = _closestPoint.Primitive;

                    if (primitive.LegendColor != Colors.Transparent && primitive.LegendLabel != null && _locked)
                    {
                        primitive.LegendLabel.IsHighlighted = true;
                    }
                }
                if ((pointChanged && _locked) || lockedChanged)
                {
                    OnClosestPointChanged();
                }
            };

            if (_dispatcher.Thread != Thread.CurrentThread)
            {
                _dispatcher.Invoke(updateGui);
            }
            else
            {
                updateGui();
            }

            return(_locked ? _closestPoint.Point : mousePos);
        }
    /// <summary>
    /// Gets the nearest point but allows for normalising the x and y
    /// by different distances, which is required if you scale the x
    /// and y seperately, but want to get the visually closest point.
    /// </summary>
    /// <param name="points"></param>
    /// <param name="point"></param>
    /// <param name="inverseNormalisation"></param>
    /// <param name="nearestDistanceSquared"></param>
    /// <returns></returns>
    public static PointAndPrimitive GetEllipseScaledNearestPoint(IEnumerable<PointAndPrimitive> points, Point point, Vector ratio, out double nearestDistanceSquared) {
      Point inverseNormalisation = new Point(1 / ratio.X, 1 / ratio.Y);

      nearestDistanceSquared = 0;

      PointAndPrimitive nearestPoint = new PointAndPrimitive(point, null);

      // Just pick off the first point to initialize stuff
      foreach(PointAndPrimitive testPoint in points) {
        nearestDistanceSquared = new Vector((testPoint.X - point.X) * inverseNormalisation.X, (testPoint.Y - point.Y) * inverseNormalisation.Y).LengthSquared;
        nearestPoint = testPoint;
        break;
      }

      // Loop through all points to find the closest
      foreach(PointAndPrimitive testPoint in points) {
        double distanceSquared = new Vector((testPoint.X - point.X) * inverseNormalisation.X, (testPoint.Y - point.Y) * inverseNormalisation.Y).LengthSquared;
        if(distanceSquared < nearestDistanceSquared) {
          nearestDistanceSquared = distanceSquared;
          nearestPoint = testPoint;
        }
      }

      return nearestPoint;
    }
    /// <summary>
    /// Handles when the mouse moves in a way that that it can execute on a thread that isn't
    /// the GUI thread.
    /// </summary>
    /// <param name="mousePos"></param>
    /// <param name="minimumBounds"></param>
    /// <returns></returns>
    public Point MouseMoved(Point mousePos, Rect minimumBounds) {

      bool newLocked = false;
      PointAndPrimitive newPoint = new PointAndPrimitive(mousePos, null);

      if(_points.Count > 0) {

        double nearestDistanceSquared;
        newPoint = GetEllipseScaledNearestPoint(_points, mousePos, (Vector)(minimumBounds.Size), out nearestDistanceSquared);
        newLocked = nearestDistanceSquared <= 1;
      }

      bool lockedChanged = newLocked != _locked;
      bool pointChanged = newPoint.Point != _closestPoint.Point;

      if(_closestPoint.Primitive != null && _closestPoint.Primitive.LegendLabel != null) {
        _closestPoint.Primitive.LegendLabel.IsHighlighted = false;
      }

      _locked = newLocked;
      _closestPoint = newPoint;

      Action updateGui = () => {
        if(_closestPoint.Primitive != null) {
          ChartPrimitive primitive = _closestPoint.Primitive;

          if(primitive.LegendColor != Colors.Transparent && primitive.LegendLabel != null && _locked) {
            primitive.LegendLabel.IsHighlighted = true;
          }
        }
        if((pointChanged && _locked) || lockedChanged) {
          OnClosestPointChanged();
        }
      };

      if(_dispatcher.Thread != Thread.CurrentThread) {
        _dispatcher.Invoke(updateGui);
      } else {
        updateGui();
      }

      return _locked ? _closestPoint.Point : mousePos;
    }