/// <summary>
        /// Retrieves the closest point on any cut to the given coordinates. This 
        /// is used for placing triggers and indicating where the disc should go
        /// </summary>
        /// <param name="pitchCoords"></param>
        /// <param name="selectionMaxDistance"></param>
        /// <param name="playerToIgnore">Compares the unique ids rather than
        /// references.</param>
        /// <param name="selectionMinDistance"></param>
        /// <returns></returns>
        public CutRatio GetClosestCutPoint(PointF pitchCoords, 
                                       float selectionMaxDistance,
                                       Player playerToIgnore,
                                       float selectionMinDistance = -1.0f)
        {
            CutRatio cutRatio = null;
              LinearMovement previousMovement = null;
              float minDistanceFromLine = selectionMaxDistance;
              LinearMovement closestMovement = null;
              LinearMovement closestPreviousMovement = null;
              Player closestPlayer = null;
              PointF triggerPoint = new PointF();

              foreach (Player player in PlayerMovement.Keys.Where(player => (playerToIgnore == null) ||
                                                                    (player.UniqueId != playerToIgnore.UniqueId)))
              {
            List<LinearMovement> playerCut = PlayerMovement[player];

            if (playerCut.Count > 1)
            {
              previousMovement = playerCut[0];
              PointF startCut = playerCut[0].FinalPosition;

              foreach (LinearMovement cutSection in PlayerMovement[player].GetRange(1, playerCut.Count - 1))
              {
            PointF endCut = cutSection.FinalPosition;
            PointF closestPoint = GeometryUtils.ClosestPointLineSegment(startCut, endCut, pitchCoords);
            float distanceFromCut = GeometryUtils.DistBetweenPoints(closestPoint, pitchCoords);

            if (distanceFromCut < minDistanceFromLine &&
                distanceFromCut > selectionMinDistance)
            {
              minDistanceFromLine = distanceFromCut;
              closestMovement = cutSection;
              closestPlayer = player;
              closestPreviousMovement = previousMovement;
              triggerPoint = closestPoint;
            }

            startCut = cutSection.FinalPosition;
            previousMovement = cutSection;
              }
            }
              }

              if (closestPlayer != null)
              {
            float cutLength = GeometryUtils.DistBetweenPoints(closestMovement.FinalPosition,
                                                          closestPreviousMovement.FinalPosition);
            float distanceToTrigger = GeometryUtils.DistBetweenPoints(closestPreviousMovement.FinalPosition,
                                                                  triggerPoint);

            cutRatio = new CutRatio();
            cutRatio.CausingCut = closestMovement;
            cutRatio.PreviousCut = closestPreviousMovement;
            cutRatio.RatioAlongCut = Math.Abs(distanceToTrigger / cutLength);
            cutRatio.Player = closestPlayer;
              }

              return cutRatio;
        }
 public Trigger(CutRatio cutRatio, Player affectedPlayer)
 {
     CausingCutRatio = cutRatio;
       AffectedPlayer = affectedPlayer;
       UniqueId = NextUniqueId++;
 }
        /// <summary>
        /// Overriding the onpopup handler (gets called before the menu is 
        /// displayed) to set up the menu based on what was clicked on.
        /// 
        /// This is to get around the fact that each player and cut is not
        /// actually a control.
        /// </summary>
        /// <param name="e"></param>
        protected override void OnPopup(EventArgs e)
        {
            this.MenuItems.Clear();

              if (mViewPanel.IsDesignMode)
              {
            // The mouse location comes in here as the location on the entire application
            // We need to use PointToClient to convert it to mouse location on the view
            // panel.
            Point mouseLocation = Cursor.Position;
            mMouseLocation = mViewPanel.PointToClient(mouseLocation);
            PointF pitchCoordinates = mViewPanel.Converter.screenToPitchCoords(mMouseLocation);
            PlayFrame currentFrame = mViewPanel.CurrentFrame;

            // Find out what was near the right click.
            mClickedPlayer = currentFrame.GetClosestPlayer(pitchCoordinates,
                                                       Settings.Default.PlayerDiameter);
            mClickedTrigger = currentFrame.GetClosestTrigger(pitchCoordinates,
                                                         Settings.Default.PlayerDiameter);
            mClickedCutRatio = mViewPanel.CurrentFrame.GetClosestCutPoint(pitchCoordinates,
                                                                      Settings.Default.PlayerDiameter,
                                                                      null);
            bool discPathClicked = currentFrame.IsOnFlightPath(pitchCoordinates,
                                                           Settings.Default.PlayerDiameter);
            if (mClickedPlayer != null)
            {
              SetUpPlayerMenu();
            }
            if (mClickedTrigger != null)
            {
              SetUpTriggerMenu();
            }
            if (mClickedCutRatio != null)
            {
              SetUpCutMenu();
            }
            if (discPathClicked)
            {
              SetUpDiscFlightMenu();
            }
            if (currentFrame.CanDrawCut(pitchCoordinates, Settings.Default.PlayerDiameter, 0.0f))
            {
              SetUpNewCutMenu();
            }

            base.OnPopup(e);
              }
        }