public virtual void handleMouseMove(Point mouseLocation, PlayFrame frame, PitchScreenCoordConverter converter, VisualOverlay overlay) { //No op for normal tools. }
public override void handleMouseDown(Point mouseLocation, PlayFrame frame, PitchScreenCoordConverter converter, VisualOverlay overlay) { if (mSelectedPlayer == null) { PointF pitchCoords = converter.screenToPitchCoords(mouseLocation); // No player is yet selected so attempt to find the one closest // to the selected spot. mSelectedPlayer = frame.GetClosestPlayer(pitchCoords, Settings.Default.PlayerDiameter * 2.0f); if (mSelectedPlayer == null) { LinearMovement prevCut = frame.GetClosestCutEnd(pitchCoords, Settings.Default.PlayerDiameter * 2.0f); if (prevCut != null && prevCut != frame.DiscFrameMovement.ReceivingCut) { mSelectedPlayer = prevCut.Player; overlay.DrawingNewCut = true; overlay.CutStart = prevCut; } } else { overlay.DrawingNewCut = true; overlay.CutStart = frame.PlayerMovement[mSelectedPlayer][0]; } } }
public override void handleMouseDown(Point mouseLocation, PlayFrame frame, PitchScreenCoordConverter converter, VisualOverlay overlay) { //Noop }
public override void handleMouseUp(Point mouseLocation, PlayFrame frame, PitchScreenCoordConverter converter, VisualOverlay overlay) { frame.AddPlayer(new Player(Team.BLUE_TEAM, "", Settings.Default.DefaultPlayerSpeed, frame.GetNextFreePlayerId(Team.BLUE_TEAM)), converter.screenToPitchCoords(mouseLocation)); IsComplete = true; ModelChanged = true; }
public override void handleMouseUp(Point mouseLocation, PlayFrame frame, PitchScreenCoordConverter converter, VisualOverlay overlay) { if (mSelectedPlayer != null) { frame.PlayerMovement[mSelectedPlayer].Add( new LinearMovement(converter.screenToPitchCoords(mouseLocation), 100, mSelectedPlayer)); IsComplete = true; ModelChanged = true; } }
public override void handleMouseUp(Point mouseLocation, PlayFrame frame, PitchScreenCoordConverter converter, VisualOverlay overlay) { PointF pitchCoords = converter.screenToPitchCoords(mouseLocation); Player closestPlayer = frame.GetClosestPlayer(pitchCoords, Settings.Default.PlayerDiameter); if (closestPlayer != null) { frame.AddDisc(closestPlayer); IsComplete = true; ModelChanged = true; } }
public override void handleMouseUp(Point mouseLocation, PlayFrame frame, PitchScreenCoordConverter converter, VisualOverlay overlay) { PointF pitchCoords = converter.screenToPitchCoords(mouseLocation); if (mSelectedPlayer != null) { // This function doesn't necessarily create a trigger but regardless // we say that the tool is complete anyway. if (frame.MaybeCreateTrigger(pitchCoords, Settings.Default.PitchLength, mSelectedPlayer)) { ModelChanged = true; } IsComplete = true; } }
/// <summary> /// In order to move an item we catch the mouse down event to decide which /// thing has been selected. This function chooses either the selected /// cut, trigger or player. /// </summary> /// <param name="mouseLocation">Screen coordinates.</param> /// <param name="frame">Frame currently being designed.</param> /// <param name="converter">Used to convert from screen to pitch /// coordinates.</param> public override void handleMouseDown(Point mouseLocation, PlayFrame frame, PitchScreenCoordConverter converter, VisualOverlay overlay) { PointF pitchCoords = converter.screenToPitchCoords(mouseLocation); // Choose closest selected item. mSelectedPlayer = frame.GetClosestPlayer(pitchCoords, SELECTION_MAX_DISTANCE); mSelectedCut = frame.GetClosestCutEnd(pitchCoords, SELECTION_MAX_DISTANCE); mSelectedTrigger = frame.GetClosestTrigger(pitchCoords, SELECTION_MAX_DISTANCE); mIsMovingDiscControlPoint = frame.IsNearControlPoint(pitchCoords, SELECTION_MAX_DISTANCE); // Note that the ordering of priorities here MUST be the same as the // ordering on mouse up. if (mSelectedTrigger != null) { overlay.SelectedTrigger = mSelectedTrigger; overlay.TriggerPlayer = mSelectedTrigger.AffectedPlayer; } else if (mSelectedCut != null) { overlay.DrawingNewCut = false; overlay.CutStart = mSelectedCut; } else if (mSelectedPlayer != null) { overlay.SelectedPlayer = mSelectedPlayer; } else if (mIsMovingDiscControlPoint) { overlay.MovingDiscControlPoint = true; } }
public override void handleMouseUp(Point mouseLocation, PlayFrame frame, PitchScreenCoordConverter converter, VisualOverlay overlay) { PointF pitchCoords = converter.screenToPitchCoords(mouseLocation); LinearMovement cut = frame.GetClosestDiscFlightPoint(pitchCoords, Settings.Default.PlayerDiameter); if (cut == null) { // The user has clicked away from any cut. They may want the disc to // go to ground so check before setting it. DialogResult result = MessageBox.Show( "You have not selected a cut to throw to, would you like the " + " disc to go here anyway", "Throw disc to ground?", MessageBoxButtons.YesNo); if (result == DialogResult.Yes) { frame.DiscFrameMovement.AbsoluteFlightPath = pitchCoords; frame.DiscFrameMovement.HasMoved = true; IsComplete = true; ModelChanged = true; } } else { frame.DiscFrameMovement.ReceivingCut = cut; frame.DiscFrameMovement.HasMoved = true; IsComplete = true; ModelChanged = true; } }
/// <summary> /// There are two components to the drawing. The first is the data model /// which is represented by a single PlayFrame. /// /// The second is a visual overlay indicating what the user is current /// doing. /// /// This function takes the frame and 'applies' the overlay to it by /// creating a deep copy and then moving/adding items as required by /// the overlay. For this to work we need to be able to uniquely /// reference items in a playmodel by an id (as their refs change on a /// deep copy). /// </summary> /// <param name="frame"></param> /// <param name="overlay"></param> /// <param name="converter"></param> /// <returns></returns> private static PlayFrame AdjustFrameForOverlay(PlayFrame frame, VisualOverlay overlay, PitchScreenCoordConverter converter) { // Take a deep copy of the frame so that we can adjust it based on what // visual overlay is required. PlayFrame adjustableFrame = frame.Clone(); PointF pitchCoords = converter.screenToPitchCoords(overlay.MouseLocation); // First move any players who need to be. if (overlay.SelectedPlayer != null) { Player movedPlayer = adjustableFrame.GetPlayerById(overlay.SelectedPlayer.UniqueId); if (movedPlayer != null) { adjustableFrame.PlayerMovement[movedPlayer][0].FinalPosition = pitchCoords; } else { adjustableFrame.AddPlayer(overlay.SelectedPlayer, pitchCoords); } } // Either a new cut is being drawn or a cut is being moved. if (overlay.CutStart != null) { if (overlay.DrawingNewCut) { Player cuttingPlayer = adjustableFrame.GetPlayerById(overlay.CutStart.Player.UniqueId); adjustableFrame.PlayerMovement[cuttingPlayer].Add( new LinearMovement(pitchCoords, 100, cuttingPlayer)); } else { LinearMovement movedCut = adjustableFrame.GetCutById(overlay.CutStart.UniqueId); adjustableFrame.ReplaceCut(movedCut, pitchCoords); } } // Check if the user is drawing the disc movement at the moment. if (overlay.DrawingDiscMovement) { adjustableFrame.DiscFrameMovement.AbsoluteFlightPath = pitchCoords; adjustableFrame.DiscFrameMovement.HasMoved = true; } if (overlay.MovingDiscControlPoint) { adjustableFrame.DiscFrameMovement.ControlPoint = pitchCoords; } // If there is a trigger being moved then the selected trigger must have // it's position updated. if (overlay.SelectedTrigger != null) { CutRatio closestCutPoint = adjustableFrame.GetClosestCutPoint(pitchCoords, sPitchLength, overlay.SelectedTrigger.AffectedPlayer); if (closestCutPoint != null) { Trigger adjustedTrigger = adjustableFrame.GetTriggerById(overlay.SelectedTrigger.UniqueId); if (adjustedTrigger != null) { adjustedTrigger.CausingCutRatio = closestCutPoint; } } } else if (overlay.PlacingTrigger) { adjustableFrame.MaybeCreateTrigger(pitchCoords, sPitchLength, overlay.TriggerPlayer); } return adjustableFrame; }
/// <summary> /// Place the disc onto the display. This must happen after the players /// are drawn so that they don't end up on top of the disc. /// </summary> /// <param name="display"></param> /// <param name="location"></param> /// <param name="converter"></param> private void DrawDisc(Graphics display, PointF location, PitchScreenCoordConverter converter) { PointF offsetCentre = new PointF(location.X, location.Y); offsetCentre.X -= ((float)Settings.Default.PlayerDiameter) / 4.0F; offsetCentre.Y -= ((float)Settings.Default.PlayerDiameter) / 4.0F; DrawSprite(display, converter, Playbook.Properties.Resources.disc, offsetCentre, Settings.Default.PlayerDiameter / 2.0f, Settings.Default.PlayerDiameter / 2.0f); }
/// <summary> /// Creates a font object with the correct size to be placed on a player. /// /// Must be disposed of by the calling code. /// </summary> /// <param name="converter"></param> /// <returns></returns> internal static Font CreatePlayerIdFont(PitchScreenCoordConverter converter) { // The player width and length in screen coordinates cannot be 0 // or the drawing will crash. int playerDiameterScreen = converter.pitchToScreenLength(Settings.Default.PlayerDiameter); if (playerDiameterScreen == 0) playerDiameterScreen = 1; int fontSize = playerDiameterScreen > 2 ? playerDiameterScreen - 2 : playerDiameterScreen; Font font = new Font("consolas", fontSize, FontStyle.Regular, GraphicsUnit.Pixel); return font; }
/// <summary> /// Draw a single player onto the given display object. The conversion /// from pitch to screen coordinates is done internally. /// </summary> /// <param name="player"></param> /// <param name="position"></param> /// <param name="display"></param> /// <param name="converter"></param> /// <param name="isSelected">A selected player shows a slightly different /// sprite to indicate the selection.</param> /// <param name="isOutline">Set to true to draw only the outline of the /// player.</param> internal void DrawPlayer(Player player, PointF position, Graphics display, PitchScreenCoordConverter converter, Boolean isOutline) { Image playerImage = isOutline ? player.PlayerTeam.OutlineSprite : player.PlayerTeam.Sprite; PointF offsetCentre = new PointF(position.X, position.Y); offsetCentre.X -= Settings.Default.PlayerDiameter / 2.0f; offsetCentre.Y -= Settings.Default.PlayerDiameter / 2.0f; DrawSprite(display, converter, playerImage, offsetCentre, Settings.Default.PlayerDiameter, Settings.Default.PlayerDiameter); using (Font font = CreatePlayerIdFont(converter)) { // Draw the player id as an overlay onto the sprite. DrawString(display, converter, player.VisibleID.ToString(CultureInfo.InvariantCulture), offsetCentre, font, Brushes.White); } }
/// <summary> /// Draw a single sprite on the pitch at the given coordinates. Does the /// conversion of pitch -> screen internally. /// </summary> /// <param name="display">The display on which to draw.</param> /// <param name="converter">The converter utility used to turn pitch /// coordinates into screen coordinates</param> /// <param name="image">The image to draw</param> /// <param name="position">The pitch coordinates</param> /// <param name="width">Pitch width</param> /// <param name="length">Pitch height/length</param> public void DrawSprite(Graphics display, PitchScreenCoordConverter converter, Image image, PointF position, float width, float length) { Rectangle imagePlacement = new Rectangle(); Point screenCoords = converter.pitchToScreenCoords(position); PointF imageSize = new PointF(width, length); Point convertedImageSize = converter.pitchToScreenSize(imageSize); imagePlacement.Location = screenCoords; imagePlacement.Width = convertedImageSize.X; imagePlacement.Height = convertedImageSize.Y; display.DrawImage(image, imagePlacement); }
/// <summary> /// Draw a string onto the pitch at the given pitch coordinates. Does /// the conversion from pitch to screen internally. /// </summary> /// <param name="display"></param> /// <param name="converter"></param> /// <param name="text"></param> /// <param name="position"></param> /// <param name="font"></param> /// <param name="brush"></param> public void DrawString(Graphics display, PitchScreenCoordConverter converter, String text, PointF position, Font font, Brush brush) { Point screenCoords = converter.pitchToScreenCoords(position); display.DrawString(text, font, brush, screenCoords); }
/// <summary> /// We capture the mouse up event and use it to place whatever it was that /// was selected on the mouse down event. If nothing was selected this does /// nothing. /// </summary> /// <param name="mouseLocation"></param> /// <param name="frame"></param> /// <param name="converter"></param> public override void handleMouseUp(Point mouseLocation, PlayFrame frame, PitchScreenCoordConverter converter, VisualOverlay overlay) { PointF pitchCoords = converter.screenToPitchCoords(mouseLocation); if (mSelectedTrigger != null) { // If we are moving a trigger then only move it if the position it is // being placed is valid. if (frame.MaybeCreateTrigger(pitchCoords, SELECTION_MAX_DISTANCE, mSelectedTrigger.AffectedPlayer)) { frame.RemoveTrigger(mSelectedTrigger); ModelChanged = true; } } else if (mSelectedPlayer != null) { frame.PlayerMovement[mSelectedPlayer][0].FinalPosition = pitchCoords; ModelChanged = true; } else if (mSelectedCut != null) { mSelectedCut.FinalPosition = pitchCoords; ModelChanged = true; } else if (mIsMovingDiscControlPoint) { frame.DiscFrameMovement.ControlPoint = pitchCoords; ModelChanged = true; } // Regardless of whether anything moved the move tool is complete on // mouse up. mSelectedCut = null; mSelectedPlayer = null; mSelectedTrigger = null; IsComplete = true; }
/// <summary> /// Render the frame into a small visible area with squares for players /// and without drawing the cuts or disc flight. /// </summary> /// <param name="frame"></param> /// <param name="display"></param> /// <param name="converter"></param> /// <param name="displayRectangle"></param> public void DrawSmallFrame(PlayFrame frame, Graphics display, PitchScreenCoordConverter converter) { display.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality; display.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; // Draw the pitch itself. DrawPitch(display, converter); foreach (Player player in frame.PlayerMovement.Keys) { DrawSmallPlayer(display, player, frame.PlayerMovement[player][0].FinalPosition, converter); } }
protected override void OnResize(EventArgs e) { using (Graphics display = this.CreateGraphics()) { Converter = new PitchScreenCoordConverter(display); } base.OnResize(e); }
/// <summary> /// Draw the disc flight. /// /// Currently simply a straight line from A to B. Could enhance this so /// that it draws a cardinal spline instead at some point. The UI to draw /// that is the more difficult area. /// </summary> /// <param name="display"></param> /// <param name="startLocation"></param> /// <param name="controlPoint"></param> /// <param name="endLocation"></param> /// <param name="converter"></param> private void DrawDiscFlight(Graphics display, PointF startLocation, PointF controlPoint, PointF endLocation, PitchScreenCoordConverter converter) { Point screenCoordsStart = converter.pitchToScreenCoords(startLocation); Point screenCoordsEnd = converter.pitchToScreenCoords(endLocation); Point screenControlPoint = converter.pitchToScreenCoords(controlPoint); QuadraticBezierCurve curve = new QuadraticBezierCurve(screenCoordsStart, screenControlPoint, screenCoordsEnd); display.DrawBeziers(mDiscFlightPen, curve.ToCubic()); display.DrawRectangle(mDiscFlightPen, screenControlPoint.X - 1, screenControlPoint.Y - 1, 2, 2); }
/// <summary> /// Draw a trigger onto the screen. The location is tied to the trigger /// object. /// /// The description of what the trigger will look like is contained wholly /// within this function. /// </summary> /// <param name="display"></param> /// <param name="trigger"></param> /// <param name="converter"></param> private void DrawTrigger(Graphics display, Trigger trigger, PitchScreenCoordConverter converter) { PointF locationToDraw = trigger.CausingCutRatio.GetAbsolutePosition(); DrawPlayer(trigger.AffectedPlayer, trigger.CausingCutRatio.GetAbsolutePosition(), display, converter, true); }
public abstract void Render(Graphics display, FrameRenderer renderer, PitchScreenCoordConverter converter);
public override void Render(Graphics display, FrameRenderer renderer, PitchScreenCoordConverter converter) { base.Render(display, renderer, converter); using (Font font = FrameRenderer.CreatePlayerIdFont(converter)) { renderer.DrawString(display, converter, ItemProperties["id"], DrawLocation, font, Brushes.White); } }
public override void Render(Graphics display, FrameRenderer renderer, PitchScreenCoordConverter converter) { // Adjust the item location so that the location is at the centre of // the image. DrawLocation = new PointF(ItemLocation.X - mWidth / 2.0f, ItemLocation.Y - mHeight / 2.0f); renderer.DrawSprite(display, converter, mSprite, DrawLocation, mWidth, mHeight); }
public abstract void handleMouseUp(Point mouseLocation, PlayFrame frame, PitchScreenCoordConverter converter, VisualOverlay overlay);
/// <summary> /// Render a small square for a player. This is used when we're rendering /// into a small space. /// </summary> /// <param name="graphics"></param> /// <param name="player"></param> /// <param name="location"></param> /// <param name="converter"></param> private void DrawSmallPlayer(Graphics graphics, Player player, PointF location, PitchScreenCoordConverter converter) { Point screenCoords = converter.pitchToScreenCoords(location); Brush playerBrush = player.PlayerTeam.UniqueId == Team.RED_TEAM.UniqueId ? Brushes.Red : Brushes.Blue; graphics.FillRectangle(playerBrush, screenCoords.X, screenCoords.Y, 4, 4); }
/// <summary> /// The pitch is drawn as a pair of rectangles rather than as a sprite. /// /// All conversion between pitch coordinates and screen coordinates is done /// internally. /// </summary> /// <param name="display"></param> /// <param name="converter"></param> public void DrawPitch(Graphics display, PitchScreenCoordConverter converter) { Rectangle outerPitch = new Rectangle(); Rectangle innerPitch = new Rectangle(); using (Pen linePen = new Pen(mLineColor, mLineWidth)) { Point bottomRight = converter.pitchToScreenCoords( new PointF(sPitchWidth, sPitchLength)); Point innerBottomRight = converter.pitchToScreenCoords( new PointF(sPitchWidth, (sPitchLength - 2.0f * sEndzoneDepth))); Point leftBrick = converter.pitchToScreenCoords( new PointF(sPitchWidth / 2.0f, sEndzoneDepth + sBrickDistance)); Point rightBrick = converter.pitchToScreenCoords( new PointF(sPitchWidth / 2.0f, sPitchLength - sEndzoneDepth - sBrickDistance)); int brickDistanceScreen = converter.pitchToScreenLength(sBrickRadius); outerPitch.Location = converter.pitchToScreenCoords(new PointF(0.0f, 0.0f)); outerPitch.Width = bottomRight.X; outerPitch.Height = bottomRight.Y; innerPitch.Location = converter.pitchToScreenCoords(new PointF(0.0f, sEndzoneDepth)); innerPitch.Width = innerBottomRight.X; innerPitch.Height = innerBottomRight.Y; display.FillRectangle(mPitchBrush, outerPitch); display.DrawRectangle(linePen, outerPitch); display.DrawRectangle(linePen, innerPitch); DrawCross(display, linePen, leftBrick, brickDistanceScreen); DrawCross(display, linePen, rightBrick, brickDistanceScreen); } }
/// <summary> /// Called whenever the underlying frame changes to redraw the frame. /// </summary> public void DrawFrame(PlayFrame frame, Graphics display, PitchScreenCoordConverter converter, VisualOverlay overlay, Rectangle displayRectangle) { BufferedGraphicsContext currentContext; BufferedGraphics myBuffer; currentContext = BufferedGraphicsManager.Current; myBuffer = currentContext.Allocate(display, displayRectangle); myBuffer.Graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality; myBuffer.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; myBuffer.Graphics.Clear(mBackColor); // Draw the pitch itself. DrawPitch(myBuffer.Graphics, converter); // This moves items around based on what the user is doing. // e.g. If a user is dragging a cut at the moment it adds a new cut for // the given player. PlayFrame adjustableFrame = FrameRenderer.AdjustFrameForOverlay(frame, overlay, converter); foreach (Player player in adjustableFrame.PlayerMovement.Keys) { List<LinearMovement> playerMoves = adjustableFrame.PlayerMovement[player]; if (playerMoves.Count > 0) { DrawPlayer(player, playerMoves[0].FinalPosition, myBuffer.Graphics, converter, false); if (playerMoves.Count > 1) { List<Point> cutLocations = new List<Point>(); foreach (LinearMovement playerMove in playerMoves) { cutLocations.Add(converter.pitchToScreenCoords(playerMove.FinalPosition)); } myBuffer.Graphics.DrawLines(mCutPen, cutLocations.ToArray<Point>()); } } } foreach (Trigger trigger in adjustableFrame.Triggers) { DrawTrigger(myBuffer.Graphics, trigger, converter); } // Draw the disc after the players because the sprite sits on top of the // player sprite who is holding it. if (adjustableFrame.DiscFrameMovement.Thrower != null) { DrawDisc(myBuffer.Graphics, adjustableFrame.DiscFrameMovement.StartPosition(), converter); if (adjustableFrame.DiscFrameMovement.HasMoved) { DrawDiscFlight(myBuffer.Graphics, adjustableFrame.DiscFrameMovement.StartPosition(), adjustableFrame.DiscFrameMovement.ControlPoint, adjustableFrame.DiscFrameMovement.EndPosition(), converter); } } else if (overlay.PlacingDisc) { // The mouse location is stored in the overlay but we need to pass the // pitch coordinates to the drawing function. DrawDisc(myBuffer.Graphics, converter.screenToPitchCoords(overlay.MouseLocation), converter); } myBuffer.Render(); myBuffer.Dispose(); }
/// <summary> /// Takes a model and outputs it as a set of images to the output directory. /// Note that if the files already exist then they'll be removed /// </summary> /// <param name="outputDir">Location for temporary images.</param> private void ModelToImageFiles(String outputDir) { mCallback.Begin(0, mModel.CycleCount / 4); Color backColor = Color.FromArgb(40, 40, 40); using (FrameRenderer renderer = new FrameRenderer(backColor, Settings.Default.PitchColor, Settings.Default.LineColor)) { using (Bitmap bitmap = new Bitmap((int)(Settings.Default.PitchLength * 10.0f), (int)(Settings.Default.PitchWidth * 10.0f))) { using (Graphics graphics = Graphics.FromImage(bitmap)) { int imageIndex = 0; FramePlayData fpd; foreach (PlayFrame frame in mModel.GetAllFrames()) { fpd = frame.GenerateViewingData(); // I made a cop out decision to allow for slow speed playback by // creating 4 times as many cycles as needed. Here though we want // to keep the output format as small as possible so only 1 in every // 4 frames is displayed. // // Frankly, this is terrible and will definitely bite me later on. int ii = 0; foreach (List<ItemPlayData> cycleData in fpd.PlayData) { ii++; if (ii % 4 != 0 && cycleData != fpd.PlayData.Last()) continue; // Thusly do I cry. PitchScreenCoordConverter converter = new PitchScreenCoordConverter(graphics); graphics.Clear(backColor); renderer.DrawPitch(graphics, converter); foreach (ItemPlayData itemPlayData in cycleData) { itemPlayData.Render(graphics, renderer, converter); } imageIndex++; BitmapExtensions.SaveJpg100(bitmap, outputDir + Path.DirectorySeparatorChar + "image" + imageIndex.ToString("D6", CultureInfo.InvariantCulture) + ".jpg"); mCallback.Increment(1); } } } } } }