/// <summary> /// Calculate the speed from the turn rate and radius. /// </summary> /// <param name="plot"></param> /// <returns></returns> private double CalculateSpeed(TurnPerformancePlot plot) { double timeToTurnCompleteCircleInSecs = 360 / plot.TurnRateInDegPerSecond; double cirumference = (plot.TurnRaduis * 2) * Math.PI; return((cirumference / 5280) / (timeToTurnCompleteCircleInSecs / 60 / 60)); }
/// <summary> /// Draw the minor title under the major title. /// </summary> /// <param name="grfx"></param> /// <param name="fastestTurnRatePlot"></param> private void DrawMinorTitle(Graphics grfx, TurnPerformancePlot fastestTurnRatePlot) { if (plots != null && plots.Count > 0) { string elapsedTimeMinorTitle = string.Format("After {0} elapsed seconds", Math.Round(this.displayTurnDegrees / fastestTurnRatePlot.TurnRateInDegPerSecond, 1)); Point minorTitlePoint = GetTitleLocationPoint(grfx); minorTitlePoint.Y += (int)TitleFont.GetHeight(); minorTitlePoint.X = (int)(this.Width / 2 - grfx.MeasureString(elapsedTimeMinorTitle, MinorTitleFont).Width / 2); grfx.DrawString(elapsedTimeMinorTitle, MinorTitleFont, MinorTitlePen.Brush, minorTitlePoint); } }
/// <summary> /// Format up the tool tip text. /// </summary> /// <param name="plot"></param> /// <returns></returns> private string GetToolTipText(TurnPerformancePlot plot) { return(string.Format(" {0}\n Turn Radius = {1} {2}\n Turn Rate = {3} degrees/second\n Turn Speed = {4} {5}\n Stall Speed = {6} {5}\n Time To Turn 360 = {7} seconds", plot.PlotTitle, Math.Round(plot.TurnRaduis, 1), TurnRadiusUnitName, Math.Round(plot.TurnRateInDegPerSecond, 1), Math.Round(CalculateSpeed(plot), 0), TurnSpeedUnitName, Math.Round(plot.StallSpeed, 1), Math.Round(360 / plot.TurnRateInDegPerSecond, 1))); }
/// <summary> /// Find the plot with the quickest turn rate. /// </summary> /// <returns></returns> private TurnPerformancePlot FindFastestTurnRate() { TurnPerformancePlot fastestTurnRatePlot = new TurnPerformancePlot(); foreach (TurnPerformancePlot plot in plots) { if (plot.TurnRateInDegPerSecond > fastestTurnRatePlot.TurnRateInDegPerSecond) { fastestTurnRatePlot = plot; } } return(fastestTurnRatePlot); }
/// <summary> /// Find the plot with the largest turn radius. /// </summary> /// <returns></returns> private TurnPerformancePlot FindLargestTurnRadius() { TurnPerformancePlot largestTurnRadiusPlot = new TurnPerformancePlot(); foreach (TurnPerformancePlot plot in plots) { if (plot.TurnRaduis > largestTurnRadiusPlot.TurnRaduis) { largestTurnRadiusPlot = plot; } } return(largestTurnRadiusPlot); }
private void BuildTurnPerformancePlot(string aircraftName, bool sustained, TurnData noFlapsData, TurnData fullFlapsData) { if (chkboxClean.Checked) { TurnPerformancePlot cleanPlot = new TurnPerformancePlot(); AddTurnPlot(cleanPlot, noFlapsData, sustained, aircraftName, TurnPerformancePlot.FlapPosition.None); } if (chkboxFullFlaps.Checked) { TurnPerformancePlot fullFlapsPlot = new TurnPerformancePlot(); AddTurnPlot(fullFlapsPlot, fullFlapsData, sustained, aircraftName, TurnPerformancePlot.FlapPosition.Full); } }
/// <summary> /// Get the point array which represents a small equlateral triangle to be used as the arc end-cap. /// </summary> /// <param name="plot"></param> /// <param name="widthOfTriangleSide"></param> /// <param name="X"></param> /// <param name="Y"></param> /// <returns></returns> private Point[] GetFlapPositionTrianglePoints(TurnPerformancePlot plot, int widthOfTriangleSide, int X, int Y) { if (plot.FlapSetting == TurnPerformancePlot.FlapPosition.None) { Point pointA = new Point(X - widthOfTriangleSide, Y + widthOfTriangleSide); Point pointB = new Point(X + widthOfTriangleSide, Y + widthOfTriangleSide); Point pointC = new Point(X, Y - widthOfTriangleSide); Point pointD = new Point(X - widthOfTriangleSide, Y + widthOfTriangleSide); return(new Point[] { pointA, pointB, pointC, pointD }); } else { Point pointA = new Point(X - widthOfTriangleSide, Y - widthOfTriangleSide); Point pointB = new Point(X + widthOfTriangleSide, Y - widthOfTriangleSide); Point pointC = new Point(X, Y + widthOfTriangleSide); Point pointD = new Point(X - widthOfTriangleSide, Y - widthOfTriangleSide); return(new Point[] { pointA, pointB, pointC, pointD }); } }
private void AddTurnPlot(TurnPerformancePlot plot, TurnData turnData, bool sustained, string aircraftName, TurnPerformancePlot.FlapPosition flapPosition) { plot.StallSpeed = turnData.StallSpeed; plot.FlapSetting = flapPosition; Pen plotPen = new Pen(Registry.Instance.AircraftColours.GetAircraftColour(aircraftName)); plotPen.Width = 1F; plot.PlotPen = plotPen; if (sustained) { plot.PlotTitle = string.Format("{0} (Sust/{1})", aircraftName, flapPosition == TurnPerformancePlot.FlapPosition.Full ? "Full Flaps" : "Clean"); plot.TurnRaduis = turnData.SustainedTurnRadius; plot.TurnRateInDegPerSecond = turnData.SustainedTurnRate; } else { plot.PlotTitle = string.Format("{0} (Inst/{1})", aircraftName, flapPosition == TurnPerformancePlot.FlapPosition.Full ? "Full Flaps" : "Clean"); plotPen.DashPattern = new float[] { 2, 2 }; plot.TurnRaduis = turnData.TurnRadiusAtCorner; plot.TurnRateInDegPerSecond = turnData.TurnRateAtCorner; } turnPerformanceUserControl.AddPlot(plot); }
private void BuildTurnPerformancePlot(string aircraftName, bool sustained, TurnData noFlapsData, TurnData fullFlapsData) { if (chkboxClean.Checked) { TurnPerformancePlot cleanPlot = new TurnPerformancePlot(); AddTurnPlot(cleanPlot, noFlapsData, sustained, aircraftName, TurnPerformancePlot.FlapPosition.None); } if(chkboxFullFlaps.Checked) { TurnPerformancePlot fullFlapsPlot = new TurnPerformancePlot(); AddTurnPlot(fullFlapsPlot, fullFlapsData, sustained, aircraftName, TurnPerformancePlot.FlapPosition.Full); } }
public void AddPlot(TurnPerformancePlot plot) { plots.Add(plot); }
/// <summary> /// Add the legend on the right hand side of the control to show which lines /// are which. /// </summary> /// <param name="grfx"></param> /// <param name="graphRectangle"></param> private void AddLegend(Graphics grfx, Rectangle graphRectangle) { if (plots.Count == 0) { return; } float maxLegendTxtWidth = 0; foreach (TurnPerformancePlot plot in plots) { SizeF size = grfx.MeasureString(plot.PlotTitle, LegendFont); if (size.Width > maxLegendTxtWidth) { maxLegendTxtWidth = size.Width; } } const int lineLength = 25; int legendHeight = LegendFont.Height * plots.Count + LegendFont.Height; int legendWidth = (int)(maxLegendTxtWidth + lineLength + 20); Point legendLocation = new Point(this.Width - legendWidth - 10, graphRectangle.Top - 5); Size legendSize = new Size(legendWidth, legendHeight); Rectangle legendRectangle = new Rectangle(legendLocation, legendSize); int shadowWidth = (int)(graphRectangle.Height / 50); Point shadowLocation = new Point(legendRectangle.Left + shadowWidth, legendRectangle.Top + shadowWidth); Rectangle shadowRectangle = new Rectangle(shadowLocation, legendSize); grfx.DrawRectangle(Pens.LightGray, shadowRectangle); grfx.FillRectangle(Brushes.LightGray, shadowRectangle.X + 1, shadowRectangle.Y + 1, shadowRectangle.Width - 1, shadowRectangle.Height - 1); grfx.DrawRectangle(Pens.Black, legendRectangle); grfx.FillRectangle(new Pen(this.BackColor).Brush, legendRectangle.X + 1, legendRectangle.Y + 1, legendRectangle.Width - 1, legendRectangle.Height - 1); for (int i = 1; i < plots.Count + 1; i++) { TurnPerformancePlot plot = plots[i - 1]; const int linePadding = 10; // Draw the plot line as the key. Point startLinePoint = new Point(legendRectangle.Left + linePadding, legendRectangle.Top + i * LegendFont.Height); Point endLinePoint = new Point(legendRectangle.Left + linePadding + lineLength, legendRectangle.Top + i * LegendFont.Height); grfx.DrawLine(plot.PlotPen, startLinePoint, endLinePoint); // draw the triangle end cap at the end of the line. int widthOfEndCap = (int)(graphRectangle.Height / 70); Pen endPointPen = new Pen(plot.PlotPen.Brush, widthOfEndCap / (float)1.3); grfx.DrawPolygon(endPointPen, GetFlapPositionTrianglePoints(plot, widthOfEndCap, endLinePoint.X, endLinePoint.Y)); // Draw the text description of the line. string legendText = plot.PlotTitle; PointF textLocationPointF = new PointF(legendRectangle.Left + lineLength + linePadding * 2, (legendRectangle.Top + i * LegendFont.Height) - (LegendFont.Height / 2)); grfx.DrawString(legendText, LegendFont, Brushes.Black, textLocationPointF); // Add the tooltip. Rectangle toolTipRectangle = new Rectangle(legendRectangle.Left, (int)textLocationPointF.Y + 2, legendRectangle.Width, LegendFont.Height - 2); tipRegionCollection.Add(new ToolTipRegion(toolTipRectangle, GetToolTipText(plot))); } }
/// <summary> /// Handle the Paint event. /// </summary> /// <param name="e"></param> protected override void OnPaint(PaintEventArgs e) { Graphics grfx = e.Graphics; Size controlSize = e.ClipRectangle.Size; DrawTitle(grfx, controlSize); int initialGraphWidth = (this.Size.Width - LeftPadding - RightPadding); int initialGraphHeight = (int)initialGraphWidth / 2; int minorGridLinesSpacing = (int)(initialGraphWidth / NumberOfMinorXAxisGridMarks); // Define the graph rectangle. The X axis runs along the bottom, the Y axis runs along the Left. Rectangle graphRectangle = new Rectangle(LeftPadding, TopPadding, NumberOfMinorXAxisGridMarks * minorGridLinesSpacing, NumberOfMinorXAxisGridMarks * minorGridLinesSpacing / 2); // Draw the graph Axis DrawGraphAxis(grfx, graphRectangle); // Draw the minor grid lines. DrawMinorGridLines(grfx, graphRectangle, minorGridLinesSpacing); TurnPerformancePlot largestTurnRadiusPlot = FindLargestTurnRadius(); float largestTurnRadius = largestTurnRadiusPlot.TurnRaduis; float largestTurnDiameter = largestTurnRadius * 2; int largestRoundedUpTurnRadius = (int)(largestTurnDiameter / UnitMultiple + 1) * UnitMultiple; int unitWidth = (int)(((largestRoundedUpTurnRadius / NumberOfMinorXAxisGridMarks) / UnitMultiple) + 1) * UnitMultiple; int widthPxBetweenMinorMarkings = (int)(graphRectangle.Width / NumberOfMinorXAxisGridMarks); // Draw X Axis minor gridline values. DrawXAxisMinorGridLineValues(grfx, graphRectangle, widthPxBetweenMinorMarkings, unitWidth); // Draw Y Axis minor gridline values. DrawYAxisMinorGridLineValues(grfx, graphRectangle, widthPxBetweenMinorMarkings, unitWidth); // Draw the axis labels. DrawAxisLabels(grfx, graphRectangle); TurnPerformancePlot fastestTurnRatePlot = FindFastestTurnRate(); // Draw the minor title. DrawMinorTitle(grfx, fastestTurnRatePlot); tipRegionCollection.Clear(); // For each plot to draw... foreach (TurnPerformancePlot plot in plots) { if (plot.TurnRateInDegPerSecond <= 0F) { continue; } float arcDegrees = plot.TurnRateInDegPerSecond * (this.displayTurnDegrees / fastestTurnRatePlot.TurnRateInDegPerSecond); int arcRadius = (int)((plot.TurnRaduis / unitWidth) * widthPxBetweenMinorMarkings); int arcBoundingRectangleLeft = LeftPadding + 1; int arcBoundingRectangleTop = (graphRectangle.Height - arcRadius) + graphRectangle.Y - 1; //Draw the turn circle. grfx.DrawArc(plot.PlotPen, new Rectangle((int)arcBoundingRectangleLeft, (int)arcBoundingRectangleTop, arcRadius * 2, arcRadius * 2), 180, arcDegrees); // Draw the 'continuation' dashed line. int widthOfDashes = (int)(graphRectangle.Height / 60); if (widthOfDashes == 0) { widthOfDashes = 1; } // draw the continuation dashed arc to complete the 180 degrees. Pen dashedPen = new Pen(Brushes.Gray); dashedPen.DashPattern = new float[] { widthOfDashes, widthOfDashes }; grfx.DrawArc(dashedPen, new Rectangle((int)arcBoundingRectangleLeft, (int)arcBoundingRectangleTop, arcRadius * 2, arcRadius * 2), 180 + arcDegrees, 180 - arcDegrees); // Find the end point of the arc so we can pop an end-cap and a label on it. int Y = (int)(arcRadius * Math.Sin(arcDegrees * Math.PI / 180)); int X = (int)(arcRadius * Math.Cos(arcDegrees * Math.PI / 180)); Y = arcBoundingRectangleTop + arcRadius - Y; X = arcBoundingRectangleLeft + arcRadius - X; // draw an end-cap at the end of the arc. int widthOfEndCap = (int)(graphRectangle.Height / 70); Pen endPointPen = new Pen(plot.PlotPen.Brush, widthOfEndCap / (float)1.3); grfx.DrawPolygon(endPointPen, GetFlapPositionTrianglePoints(plot, widthOfEndCap, X, Y)); Point toolTipPoint = new Point(X - (widthOfEndCap / 2) * 2 + 1, Y - (widthOfEndCap / 2) * 2 + 1); Rectangle toolTipRectangle = new Rectangle(toolTipPoint.X - widthOfEndCap, toolTipPoint.Y - widthOfEndCap, widthOfEndCap * 3, widthOfEndCap * 3); tipRegionCollection.Add(new ToolTipRegion(toolTipRectangle, GetToolTipText(plot))); } AddLegend(grfx, graphRectangle); if (ShowToolTipRegions) { foreach (ToolTipRegion region in tipRegionCollection) { grfx.DrawRectangle(new Pen(Brushes.Black, 2f), region.Region); } } }