/// <summary> /// Draws the line plot on a GDI+ surface against the provided x and y axes. /// </summary> /// <param name="g">The GDI+ surface on which to draw.</param> /// <param name="xAxis">The X-Axis to draw against.</param> /// <param name="yAxis">The Y-Axis to draw against.</param> public void Draw(Graphics g, PhysicalAxis xAxis, PhysicalAxis yAxis) { try { double xVal, yVal; int pointCount = m_lineData.Count; if (pointCount == 0) { return; } Stopwatch sw = StepTimer.Start("Transform"); Transform2D t = new Transform2D(xAxis, yAxis); // clipping is now handled assigning a clip region in the // graphic object before this call if (pointCount == 1) { m_lineData.Get(0, out xVal, out yVal); PointF physical = t.Transform(xVal, yVal); g.DrawLine(Pen, physical.X - 0.5f, physical.Y, physical.X + 0.5f, physical.Y); } else { int index = 0; PointF[] points = new PointF[pointCount]; PointF lastPoint = new PointF(Single.NaN, Single.NaN); for (int i = 0; i < pointCount; ++i) { // check to see if any values null. If so, then continue. m_lineData.Get(i, out xVal, out yVal); if (!Double.IsNaN(xVal + yVal)) //Adding a NaN with anything yeilds NaN { const float GDIMax = 1000000000f; const float GDIMin = -1000000000f; PointF p1 = t.Transform(xVal, yVal); if (p1.X > GDIMax) { p1.X = GDIMax; } if (p1.X < GDIMin) { p1.X = GDIMin; } if (p1.Y > GDIMax) { p1.Y = GDIMax; } if (p1.Y < GDIMin) { p1.Y = GDIMin; } if (!float.IsNaN(p1.X) && !float.IsNaN(p1.Y)) { if (p1 != lastPoint) { lastPoint = p1; points[index] = p1; index++; } } } } //System.Drawing.Drawing2D.GraphicsPath graphicsPath = new System.Drawing.Drawing2D.GraphicsPath(); //graphicsPath.AddLines(points.ToArray()); //g.DrawPath(Pen, graphicsPath); //g.CompositingQuality = CompositingQuality.HighQuality; //g.SmoothingMode = SmoothingMode.HighQuality; StepTimer.Stop(sw); sw = StepTimer.Start("GDI+"); if (index == 0) { return; } else if (index == 1) { PointF physical = points[0]; g.DrawLine(Pen, physical.X - 0.5f, physical.Y, physical.X + 0.5f, physical.Y); return; } if (index == points.Length) { g.DrawLines(Pen, points); } else { PointF[] newArray = new PointF[index]; Array.Copy(points, 0, newArray, 0, index); g.DrawLines(Pen, newArray); } StepTimer.Stop(sw); } } catch (Exception ex) { MessageBox.Show(ex.ToString()); throw; } }
/// <summary> /// Draw the the PlotSurface2D and all contents [axes, drawables] on the /// supplied graphics surface. /// </summary> /// <param name="g">The graphics surface on which to draw.</param> /// <param name="bounds">A bounding box on this surface that denotes the area on the /// surface to confine drawing to.</param> public void Draw(Graphics g, Rectangle bounds) { // determine font sizes and tick scale factor. float scale = DetermineScaleFactor(bounds.Width, bounds.Height); // if there is nothing to plot, return. if (m_drawables.Count == 0) { // draw title float x_center = (bounds.Left + bounds.Right) / 2.0f; float y_center = (bounds.Top + bounds.Bottom) / 2.0f; Font scaled_font; if (AutoScaleTitle) { scaled_font = Utils.ScaleFont(m_titleFont, scale); } else { scaled_font = m_titleFont; } g.DrawString(m_title, scaled_font, this.m_titleBrush, new PointF(x_center, y_center), m_titleDrawFormat); return; } Stopwatch sw = StepTimer.Start("Determine Axis"); // determine the [non physical] axes to draw based on the axis properties set. Axis xAxis1, xAxis2, yAxis1, yAxis2; DetermineAxesToDraw(out xAxis1, out xAxis2, out yAxis1, out yAxis2); // apply scale factor to axes as desired. if (xAxis1.AutoScaleTicks) { xAxis1.TickScale = scale; } if (xAxis1.AutoScaleText) { xAxis1.FontScale = scale; } if (yAxis1.AutoScaleTicks) { yAxis1.TickScale = scale; } if (yAxis1.AutoScaleText) { yAxis1.FontScale = scale; } if (xAxis2.AutoScaleTicks) { xAxis2.TickScale = scale; } if (xAxis2.AutoScaleText) { xAxis2.FontScale = scale; } if (yAxis2.AutoScaleTicks) { yAxis2.TickScale = scale; } if (yAxis2.AutoScaleText) { yAxis2.FontScale = scale; } // determine the default physical positioning of those axes. PhysicalAxis pXAxis1, pYAxis1, pXAxis2, pYAxis2; DeterminePhysicalAxesToDraw(bounds, xAxis1, xAxis2, yAxis1, yAxis2, out pXAxis1, out pXAxis2, out pYAxis1, out pYAxis2); StepTimer.Stop(sw); float oldXAxis2Height = pXAxis2.PhysicalMin.Y; // Apply axes constraints for (int i = 0; i < m_axesConstraints.Count; ++i) { (m_axesConstraints[i]).ApplyConstraint(pXAxis1, pYAxis1, pXAxis2, pYAxis2); } float newXAxis2Height = pXAxis2.PhysicalMin.Y; float titleExtraOffset = oldXAxis2Height - newXAxis2Height; sw = StepTimer.Start("Draw Axis"); // now we are ready to define the bounding box for the plot area (to use in clipping // operations. m_plotAreaBoundingBoxCache = new Rectangle( Math.Min(pXAxis1.PhysicalMin.X, pXAxis1.PhysicalMax.X), Math.Min(pYAxis1.PhysicalMax.Y, pYAxis1.PhysicalMin.Y), Math.Abs(pXAxis1.PhysicalMax.X - pXAxis1.PhysicalMin.X + 1), Math.Abs(pYAxis1.PhysicalMin.Y - pYAxis1.PhysicalMax.Y + 1) ); m_bbXAxis1Cache = pXAxis1.GetBoundingBox(); m_bbXAxis2Cache = pXAxis2.GetBoundingBox(); m_bbYAxis1Cache = pYAxis1.GetBoundingBox(); m_bbYAxis2Cache = pYAxis2.GetBoundingBox(); // Fill in the background. g.FillRectangle(new SolidBrush(m_plotBackColor), m_plotAreaBoundingBoxCache); // draw title float xt = (pXAxis2.PhysicalMax.X + pXAxis2.PhysicalMin.X) / 2.0f; float yt = bounds.Top + m_padding - titleExtraOffset; Font scaledFont; if (AutoScaleTitle) { scaledFont = Utils.ScaleFont(m_titleFont, scale); } else { scaledFont = m_titleFont; } g.DrawString(m_title, scaledFont, m_titleBrush, new PointF(xt, yt), m_titleDrawFormat); //count number of new lines in title. int nlCount = 0; for (int i = 0; i < m_title.Length; ++i) { if (m_title[i] == '\n') { nlCount += 1; } } SizeF s = g.MeasureString(m_title, scaledFont); m_bbTitleCache = new Rectangle((int)(xt - s.Width / 2), (int)(yt), (int)(s.Width), (int)(s.Height) * (nlCount + 1)); StepTimer.Stop(sw); //sw = StepTimer.Start("Draw IDrawables"); // draw drawables.. SmoothingMode smoothSave = g.SmoothingMode; g.SmoothingMode = m_smoothingMode; for (int i_o = 0; i_o < m_ordering.Count; ++i_o) { int i = m_ordering.Values[i_o]; IDrawable drawable = m_drawables[i]; PhysicalAxis drawXAxis; PhysicalAxis drawYAxis; drawXAxis = pXAxis1; drawYAxis = pYAxis1; // set the clipping region.. (necessary for zoom) g.Clip = new Region(m_plotAreaBoundingBoxCache); // plot. drawable.Draw(g, drawXAxis, drawYAxis); // reset it.. g.ResetClip(); } //StepTimer.Stop(sw); // cache the physical axes we used on this draw; m_pXAxis1Cache = pXAxis1; m_pYAxis1Cache = pYAxis1; m_pXAxis2Cache = pXAxis2; m_pYAxis2Cache = pYAxis2; g.SmoothingMode = smoothSave; sw = StepTimer.Start("Draw Axis Final"); // now draw axes. Rectangle axisBounds; pXAxis1.Draw(g, out axisBounds); pXAxis2.Draw(g, out axisBounds); pYAxis1.Draw(g, out axisBounds); pYAxis2.Draw(g, out axisBounds); StepTimer.Stop(sw); }