/// <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); } }