Beispiel #1
0
		/// <summary>
		/// Draw the this <see c_ref="CurveItem"/> to the specified <see c_ref="Graphics"/>
		/// device.  The format (stair-step or line) of the curve is
		/// defined by the <see c_ref="StepType"/> property.  The routine
		/// only draws the line segments; the symbols are drawn by the
		/// <see c_ref="Symbol.Draw"/> method.  This method
		/// is normally only called by the Draw method of the
		/// <see c_ref="CurveItem"/> object
		/// </summary>
		/// <param name="g">
		/// A graphic device object to be drawn into.  This is normally e.Graphics from the
		/// PaintEventArgs argument to the Paint() method.
		/// </param>
		/// <param name="scaleFactor">
		/// The scaling factor to be used for rendering objects.  This is calculated and
		/// passed down by the parent <see c_ref="GraphPane"/> object using the
		/// <see c_ref="PaneBase.CalcScaleFactor"/> method, and is used to proportionally adjust
		/// font sizes, etc. according to the actual size of the graph.
		/// </param>
		/// <param name="pane">
		/// A reference to the <see c_ref="GraphPane"/> object that is the parent or
		/// owner of this object.
		/// </param>
		/// <param name="curve">A <see c_ref="LineItem"/> representing this
		/// curve.</param>
		public void DrawCurveOriginal( Graphics g, GraphPane pane,
										  CurveItem curve, float scaleFactor )
		{
			Line source = this;
			if ( curve.IsSelected )
				source = Selection.Line;

			float tmpX, tmpY,
					lastX = float.MaxValue,
					lastY = float.MaxValue;
			double curX, curY, lowVal;
			PointPair curPt, lastPt = new PointPair();

			bool lastBad = true;
			IPointList points = curve.Points;
			ValueHandler valueHandler = new ValueHandler( pane, false );
			Axis yAxis = curve.GetYAxis( pane );
			Axis xAxis = curve.GetXAxis( pane );

			bool xIsLog = xAxis._scale.IsLog;
			bool yIsLog = yAxis._scale.IsLog;

			float minX = pane.Chart.Rect.Left;
			float maxX = pane.Chart.Rect.Right;
			float minY = pane.Chart.Rect.Top;
			float maxY = pane.Chart.Rect.Bottom;

			using ( Pen pen = source.GetPen( pane, scaleFactor ) )
			{
				if ( points != null && !_color.IsEmpty && IsVisible )
				{
					//bool lastOut = false;
					bool isOut;

					// Loop over each point in the curve
					for ( int i = 0; i < points.Count; i++ )
					{
						curPt = points[i];
						if ( pane.LineType == LineType.Stack )
						{
							if ( !valueHandler.GetValues( curve, i, out curX, out lowVal, out curY ) )
							{
								curX = PointPair.Missing;
								curY = PointPair.Missing;
							}
						}
						else
						{
							curX = curPt.X;
							curY = curPt.Y;
						}

						// Any value set to double max is invalid and should be skipped
						// This is used for calculated values that are out of range, divide
						//   by zero, etc.
						// Also, any value <= zero on a log scale is invalid
						if ( curX == PointPair.Missing ||
								curY == PointPair.Missing ||
								Double.IsNaN( curX ) ||
								Double.IsNaN( curY ) ||
								Double.IsInfinity( curX ) ||
								Double.IsInfinity( curY ) ||
								( xIsLog && curX <= 0.0 ) ||
								( yIsLog && curY <= 0.0 ) )
						{
							// If the point is invalid, then make a linebreak only if IsIgnoreMissing is false
							// LastX and LastY are always the last valid point, so this works out
							lastBad = lastBad || !pane.IsIgnoreMissing;
							isOut = true;
						}
						else
						{
							// Transform the current point from user scale units to
							// screen coordinates
							tmpX = xAxis.Scale.Transform( curve.IsOverrideOrdinal, i, curX );
							tmpY = yAxis.Scale.Transform( curve.IsOverrideOrdinal, i, curY );
							isOut = ( tmpX < minX && lastX < minX ) || ( tmpX > maxX && lastX > maxX ) ||
								( tmpY < minY && lastY < minY ) || ( tmpY > maxY && lastY > maxY );

							if ( !lastBad )
							{
								try
								{
									// GDI+ plots the data wrong and/or throws an exception for
									// outrageous coordinates, so we do a sanity check here
									if ( lastX > 5000000 || lastX < -5000000 ||
											lastY > 5000000 || lastY < -5000000 ||
											tmpX > 5000000 || tmpX < -5000000 ||
											tmpY > 5000000 || tmpY < -5000000 )
										InterpolatePoint( g, pane, curve, lastPt, scaleFactor, pen,
														lastX, lastY, tmpX, tmpY );
									else if ( !isOut )
									{
										if ( !curve.IsSelected && _gradientFill.IsGradientValueType )
										{
											using ( Pen tPen = GetPen( pane, scaleFactor, lastPt ) )
											{
												if ( StepType == StepType.NonStep )
												{
													g.DrawLine( tPen, lastX, lastY, tmpX, tmpY );
												}
												else if ( StepType == StepType.ForwardStep )
												{
													g.DrawLine( tPen, lastX, lastY, tmpX, lastY );
													g.DrawLine( tPen, tmpX, lastY, tmpX, tmpY );
												}
												else if ( StepType == StepType.RearwardStep )
												{
													g.DrawLine( tPen, lastX, lastY, lastX, tmpY );
													g.DrawLine( tPen, lastX, tmpY, tmpX, tmpY );
												}
												else if ( StepType == StepType.ForwardSegment )
												{
													g.DrawLine( tPen, lastX, lastY, tmpX, lastY );
												}
												else
												{
													g.DrawLine( tPen, lastX, tmpY, tmpX, tmpY );
												}
											}
										}
										else
										{
											if ( StepType == StepType.NonStep )
											{
												g.DrawLine( pen, lastX, lastY, tmpX, tmpY );
											}
											else if ( StepType == StepType.ForwardStep )
											{
												g.DrawLine( pen, lastX, lastY, tmpX, lastY );
												g.DrawLine( pen, tmpX, lastY, tmpX, tmpY );
											}
											else if ( StepType == StepType.RearwardStep )
											{
												g.DrawLine( pen, lastX, lastY, lastX, tmpY );
												g.DrawLine( pen, lastX, tmpY, tmpX, tmpY );
											}
											else if ( StepType == StepType.ForwardSegment )
											{
												g.DrawLine( pen, lastX, lastY, tmpX, lastY );
											}
											else if ( StepType == StepType.RearwardSegment )
											{
												g.DrawLine( pen, lastX, tmpY, tmpX, tmpY );
											}
										}
									}

								}
								catch
								{
									InterpolatePoint( g, pane, curve, lastPt, scaleFactor, pen,
												lastX, lastY, tmpX, tmpY );
								}

							}

							lastPt = curPt;
							lastX = tmpX;
							lastY = tmpY;
							lastBad = false;
							//lastOut = isOut;
						}
					}
				}
			}
		}
Beispiel #2
0
		/// <summary>
		/// Create a URL for a <see c_ref="CurveItem" /> that includes the index of the
		/// point that was selected.
		/// </summary>
		/// <remarks>
		/// An "index" parameter is added to the <see c_ref="Url" /> property for this
		/// link to indicate which point was selected.  Further, if the 
		/// X or Y axes that correspond to this <see c_ref="CurveItem" /> are of
		/// <see c_ref="AxisType.Text" />, then an
		/// additional parameter will be added containing the text value that
		/// corresponds to the <paramref name="index" /> of the selected point.
		/// The <see c_ref="XAxis" /> text parameter will be labeled "xtext", and
		/// the <see c_ref="YAxis" /> text parameter will be labeled "ytext".
		/// </remarks>
		/// <param name="index">The zero-based index of the selected point</param>
		/// <param name="pane">The <see c_ref="GraphPane" /> of interest</param>
		/// <param name="curve">The <see c_ref="CurveItem" /> for which to
		/// make the url string.</param>
		/// <returns>A string containing the url with an index parameter added.</returns>
		public virtual string MakeCurveItemUrl( GraphPane pane, CurveItem curve, int index )
		{
			string url = _url;

			if ( url.IndexOf( '?' ) >= 0 )
				url += "&index=" + index;
			else
				url += "?index=" + index;

			Axis xAxis = curve.GetXAxis( pane );
			if (	xAxis.Type == AxisType.Text && index >= 0 &&
					xAxis.Scale.TextLabels != null &&
					index <= xAxis.Scale.TextLabels.Length )
				url += "&xtext=" + xAxis.Scale.TextLabels[index];

			Axis yAxis = curve.GetYAxis( pane );
			if (	yAxis != null && yAxis.Type == AxisType.Text && index >= 0 &&
					yAxis.Scale.TextLabels != null &&
					index <= yAxis.Scale.TextLabels.Length )
				url += "&ytext=" + yAxis.Scale.TextLabels[index];

			return url;
		}
Beispiel #3
0
		/// <summary>
		/// Draw the this <see c_ref="CurveItem"/> to the specified <see c_ref="Graphics"/>
		/// device using the specified smoothing property (<see c_ref="ZedGraph.Line.SmoothTension"/>).
		/// The routine draws the line segments and the area fill (if any, see <see c_ref="FillType"/>;
		/// the symbols are drawn by the <see c_ref="Symbol.Draw"/> method.  This method
		/// is normally only called by the Draw method of the
		/// <see c_ref="CurveItem"/> object.  Note that the <see c_ref="StepType"/> property
		/// is ignored for smooth lines (e.g., when <see c_ref="ZedGraph.Line.IsSmooth"/> is true).
		/// </summary>
		/// <param name="g">
		/// A graphic device object to be drawn into.  This is normally e.Graphics from the
		/// PaintEventArgs argument to the Paint() method.
		/// </param>
		/// <param name="scaleFactor">
		/// The scaling factor to be used for rendering objects.  This is calculated and
		/// passed down by the parent <see c_ref="GraphPane"/> object using the
		/// <see c_ref="PaneBase.CalcScaleFactor"/> method, and is used to proportionally adjust
		/// font sizes, etc. according to the actual size of the graph.
		/// </param>
		/// <param name="pane">
		/// A reference to the <see c_ref="GraphPane"/> object that is the parent or
		/// owner of this object.
		/// </param>
		/// <param name="curve">A <see c_ref="LineItem"/> representing this
		/// curve.</param>
		public void DrawSmoothFilledCurve( Graphics g, GraphPane pane,
                                CurveItem curve, float scaleFactor )
		{
			Line source = this;
			if ( curve.IsSelected )
				source = Selection.Line;

			PointF[] arrPoints;
			int count;
			IPointList points = curve.Points;

			if ( IsVisible && !Color.IsEmpty && points != null &&
				BuildPointsArray( pane, curve, out arrPoints, out count ) &&
				count > 2 )
			{
				float tension = _isSmooth ? _smoothTension : 0f;

				// Fill the curve if needed
				if ( Fill.IsVisible )
				{
					Axis yAxis = curve.GetYAxis( pane );

					using ( GraphicsPath path = new GraphicsPath( FillMode.Winding ) )
					{
						path.AddCurve( arrPoints, 0, count - 2, tension );

						double yMin = yAxis._scale._min < 0 ? 0.0 : yAxis._scale._min;
						CloseCurve( pane, curve, arrPoints, count, yMin, path );

						RectangleF rect = path.GetBounds();
						using ( Brush brush = source._fill.MakeBrush( rect ) )
						{
							if ( pane.LineType == LineType.Stack && yAxis.Scale._min < 0 &&
									IsFirstLine( pane, curve ) )
							{
								float zeroPix = yAxis.Scale.Transform( 0 );
								RectangleF tRect = pane.Chart._rect;
								tRect.Height = zeroPix - tRect.Top;
								if ( tRect.Height > 0 )
								{
									Region reg = g.Clip;
									g.SetClip( tRect );
									g.FillPath( brush, path );
									g.SetClip( pane.Chart._rect );
								}
							}
							else
								g.FillPath( brush, path );
							//brush.Dispose();
						}

						// restore the zero line if needed (since the fill tends to cover it up)
						yAxis.FixZeroLine( g, pane, scaleFactor, rect.Left, rect.Right );
					}
				}

				// If it's a smooth curve, go ahead and render the path.  Otherwise, use the
				// standard drawcurve method just in case there are missing values.
				if ( _isSmooth )
				{
					using ( Pen pen = GetPen( pane, scaleFactor ) )
					{
						// Stroke the curve
						g.DrawCurve( pen, arrPoints, 0, count - 2, tension );

						//pen.Dispose();
					}
				}
				else
					DrawCurve( g, pane, curve, scaleFactor );
			}
		}
Beispiel #4
0
		/// <summary>
		/// Render the <see c_ref="Line"/>'s as vertical sticks (from a <see c_ref="StickItem" />) to
		/// the specified <see c_ref="Graphics"/> device.
		/// </summary>
		/// <param name="g">
		/// A graphic device object to be drawn into.  This is normally e.Graphics from the
		/// PaintEventArgs argument to the Paint() method.
		/// </param>
		/// <param name="pane">
		/// A reference to the <see c_ref="ZedGraph.GraphPane"/> object that is the parent or
		/// owner of this object.
		/// </param>
		/// <param name="curve">A <see c_ref="CurveItem"/> representing this
		/// curve.</param>
		/// <param name="scaleFactor">
		/// The scaling factor to be used for rendering objects.  This is calculated and
		/// passed down by the parent <see c_ref="GraphPane"/> object using the
		/// <see c_ref="PaneBase.CalcScaleFactor"/> method, and is used to proportionally adjust
		/// font sizes, etc. according to the actual size of the graph.
		/// </param>
		public void DrawSticks( Graphics g, GraphPane pane, CurveItem curve, float scaleFactor )
		{
			Line source = this;
			if ( curve.IsSelected )
				source = Selection.Line;

			Axis yAxis = curve.GetYAxis( pane );
			Axis xAxis = curve.GetXAxis( pane );

			float basePix = yAxis.Scale.Transform( 0.0 );
			using ( Pen pen = source.GetPen( pane, scaleFactor ) )
			{
				for ( int i = 0; i < curve.Points.Count; i++ )
				{
					PointPair pt = curve.Points[i];

					if ( pt.X != PointPair.Missing &&
							pt.Y != PointPair.Missing &&
							!Double.IsNaN( pt.X ) &&
							!Double.IsNaN( pt.Y ) &&
							!Double.IsInfinity( pt.X ) &&
							!Double.IsInfinity( pt.Y ) &&
							( !xAxis._scale.IsLog || pt.X > 0.0 ) &&
							( !yAxis._scale.IsLog || pt.Y > 0.0 ) )
					{
						float pixY = yAxis.Scale.Transform( curve.IsOverrideOrdinal, i, pt.Y );
						float pixX = xAxis.Scale.Transform( curve.IsOverrideOrdinal, i, pt.X );

						if ( pixX >= pane.Chart._rect.Left && pixX <= pane.Chart._rect.Right )
						{
							if ( pixY > pane.Chart._rect.Bottom )
								pixY = pane.Chart._rect.Bottom;
							if ( pixY < pane.Chart._rect.Top )
								pixY = pane.Chart._rect.Top;

							if ( !curve.IsSelected && _gradientFill.IsGradientValueType )
							{
								using ( Pen tPen = GetPen( pane, scaleFactor, pt ) )
									g.DrawLine( tPen, pixX, pixY, pixX, basePix );
							}
							else
								g.DrawLine( pen, pixX, pixY, pixX, basePix );

						}
					}
				}
			}
		}
Beispiel #5
0
		/// <summary>
		/// Close off a <see c_ref="GraphicsPath"/> that defines a curve
		/// </summary>
		/// <param name="pane">A reference to the <see c_ref="GraphPane"/> object that is the parent or
		/// owner of this object.</param>
		/// <param name="curve">A <see c_ref="LineItem"/> representing this
		/// curve.</param>
		/// <param name="arrPoints">An array of <see c_ref="PointF"/> values in screen pixel
		/// coordinates representing the current curve.</param>
		/// <param name="count">The number of points contained in the "arrPoints"
		/// parameter.</param>
		/// <param name="yMin">The Y axis value location where the X axis crosses.</param>
		/// <param name="path">The <see c_ref="GraphicsPath"/> class that represents the curve.</param>
		public void CloseCurve( GraphPane pane, CurveItem curve, PointF[] arrPoints,
									int count, double yMin, GraphicsPath path )
		{
			// For non-stacked lines, the fill area is just the area between the curve and the X axis
			if ( pane.LineType != LineType.Stack )
			{
				// Determine the current value for the bottom of the curve (usually the Y value where
				// the X axis crosses)
				float yBase;
				Axis yAxis = curve.GetYAxis( pane );
				yBase = yAxis.Scale.Transform( yMin );

				// Add three points to the path to move from the end of the curve (as defined by
				// arrPoints) to the X axis, from there to the start of the curve at the X axis,
				// and from there back up to the beginning of the curve.
				path.AddLine( arrPoints[count - 1].X, arrPoints[count - 1].Y, arrPoints[count - 1].X, yBase );
				path.AddLine( arrPoints[count - 1].X, yBase, arrPoints[0].X, yBase );
				path.AddLine( arrPoints[0].X, yBase, arrPoints[0].X, arrPoints[0].Y );
			}
			// For stacked line types, the fill area is the area between this curve and the curve below it
			else
			{
				PointF[] arrPoints2;
				int count2;

				float tension = _isSmooth ? _smoothTension : 0f;

				// Find the next lower curve in the curveList that is also a LineItem type, and use
				// its smoothing properties for the lower side of the filled area.
				int index = pane.CurveList.IndexOf( curve );
				if ( index > 0 )
				{
					CurveItem tmpCurve;
					for ( int i = index - 1; i >= 0; i-- )
					{
						tmpCurve = pane.CurveList[i];
						if ( tmpCurve is LineItem )
						{
							tension = ( (LineItem)tmpCurve ).Line.IsSmooth ? ( (LineItem)tmpCurve ).Line.SmoothTension : 0f;
							break;
						}
					}
				}

				// Build another points array consisting of the low points (which are actually the points for
				// the curve below the current curve)
				BuildLowPointsArray( pane, curve, out arrPoints2, out count2 );

				// Add the new points to the GraphicsPath
				path.AddCurve( arrPoints2, 0, count2 - 2, tension );
			}

		}
Beispiel #6
0
		/// <summary>
		/// Build an array of <see c_ref="PointF"/> values (pixel coordinates) that represents
		/// the low values for the current curve.
		/// </summary>
		/// <remarks>Note that this drawing routine ignores <see c_ref="PointPairBase.Missing"/>
		/// values, but it does not "break" the line to indicate values are missing.
		/// </remarks>
		/// <param name="pane">A reference to the <see c_ref="GraphPane"/> object that is the parent or
		/// owner of this object.</param>
		/// <param name="curve">A <see c_ref="LineItem"/> representing this
		/// curve.</param>
		/// <param name="arrPoints">An array of <see c_ref="PointF"/> values in pixel
		/// coordinates representing the current curve.</param>
		/// <param name="count">The number of points contained in the "arrPoints"
		/// parameter.</param>
		/// <returns>true for a successful points array build, false for data problems</returns>
		public bool BuildLowPointsArray( GraphPane pane, CurveItem curve,
						out PointF[] arrPoints, out int count )
		{
			arrPoints = null;
			count = 0;
			IPointList points = curve.Points;

			if ( IsVisible && !Color.IsEmpty && points != null )
			{
				int index = 0;
				float curX, curY,
						lastX = 0,
						lastY = 0;
				double x, y, hiVal;
				ValueHandler valueHandler = new ValueHandler( pane, false );

				// Step type plots get twice as many points.  Always add three points so there is
				// room to close out the curve for area fills.
                arrPoints = new PointF[(_stepType == StepType.NonStep ? 1 : 2) *
					( pane.LineType == LineType.Stack ? 2 : 1 ) *
					points.Count + 1];

				// Loop backwards over all points in the curve
				// In this case an array of points was already built forward by BuildPointsArray().
				// This time we build backwards to complete a loop around the area between two curves.
				for ( int i = points.Count - 1; i >= 0; i-- )
				{
					// Make sure the current point is valid
					if ( !points[i].IsInvalid )
					{
						// Get the user scale values for the current point
						valueHandler.GetValues( curve, i, out x, out y, out hiVal );

						if ( x == PointPair.Missing || y == PointPair.Missing )
							continue;

						// Transform the user scale values to pixel locations
						Axis xAxis = curve.GetXAxis( pane );
						curX = xAxis.Scale.Transform( curve.IsOverrideOrdinal, i, x );
						Axis yAxis = curve.GetYAxis( pane );
						curY = yAxis.Scale.Transform( curve.IsOverrideOrdinal, i, y );

						// Add the pixel value pair into the points array
						// Two points are added for step type curves
						// ignore step-type setting for smooth curves
						if ( _isSmooth || index == 0 || StepType == StepType.NonStep )
						{
							arrPoints[index].X = curX;
							arrPoints[index].Y = curY;
						}
						else if ( StepType == StepType.ForwardStep )
						{
							arrPoints[index].X = curX;
							arrPoints[index].Y = lastY;
							index++;
							arrPoints[index].X = curX;
							arrPoints[index].Y = curY;
						}
						else if ( StepType == StepType.RearwardStep )
						{
							arrPoints[index].X = lastX;
							arrPoints[index].Y = curY;
							index++;
							arrPoints[index].X = curX;
							arrPoints[index].Y = curY;
						}

						lastX = curX;
						lastY = curY;
						index++;

					}

				}

				// Make sure there is at least one valid point
				if ( index == 0 )
					return false;

				// Add an extra point at the end, since the smoothing algorithm requires it
				arrPoints[index] = arrPoints[index - 1];
				index++;

				count = index;
				return true;
			}
		    return false;
		}
Beispiel #7
0
		/// <summary>
		/// Build an array of <see c_ref="PointF"/> values (pixel coordinates) that represents
		/// the current curve.  Note that this drawing routine ignores <see c_ref="PointPairBase.Missing"/>
		/// values, but it does not "break" the line to indicate values are missing.
		/// </summary>
		/// <param name="pane">A reference to the <see c_ref="GraphPane"/> object that is the parent or
		/// owner of this object.</param>
		/// <param name="curve">A <see c_ref="LineItem"/> representing this
		/// curve.</param>
		/// <param name="arrPoints">An array of <see c_ref="PointF"/> values in pixel
		/// coordinates representing the current curve.</param>
		/// <param name="count">The number of points contained in the "arrPoints"
		/// parameter.</param>
		/// <returns>true for a successful points array build, false for data problems</returns>
		public bool BuildPointsArray( GraphPane pane, CurveItem curve,
			out PointF[] arrPoints, out int count )
		{
			arrPoints = null;
			count = 0;
			IPointList points = curve.Points;

			if ( IsVisible && !Color.IsEmpty && points != null )
			{
				int index = 0;
				float curX, curY,
							lastX = 0,
							lastY = 0;
				double x, y, lowVal;
				ValueHandler valueHandler = new ValueHandler( pane, false );

				// Step type plots get twice as many points.  Always add three points so there is
				// room to close out the curve for area fills.
                arrPoints = new PointF[(_stepType == StepType.NonStep ? 1 : 2) *
											points.Count + 1];

				// Loop over all points in the curve
				for ( int i = 0; i < points.Count; i++ )
				{
					// make sure that the current point is valid
					if ( !points[i].IsInvalid )
					{
						// Get the user scale values for the current point
						// use the valueHandler only for stacked types
						if ( pane.LineType == LineType.Stack )
						{
							valueHandler.GetValues( curve, i, out x, out lowVal, out y );
						}
						// otherwise, just access the values directly.  Avoiding the valueHandler for
						// non-stacked types is an optimization to minimize overhead in case there are
						// a large number of points.
						else
						{
							x = points[i].X;
							y = points[i].Y;
						}

						if ( x == PointPair.Missing || y == PointPair.Missing )
							continue;

						// Transform the user scale values to pixel locations
						Axis xAxis = curve.GetXAxis( pane );
						curX = xAxis.Scale.Transform( curve.IsOverrideOrdinal, i, x );
						Axis yAxis = curve.GetYAxis( pane );
						curY = yAxis.Scale.Transform( curve.IsOverrideOrdinal, i, y );

						if ( curX < -1000000 || curY < -1000000 || curX > 1000000 || curY > 1000000 )
							continue;

						// Add the pixel value pair into the points array
						// Two points are added for step type curves
						// ignore step-type setting for smooth curves
						if ( _isSmooth || index == 0 || StepType == StepType.NonStep )
						{
							arrPoints[index].X = curX;
							arrPoints[index].Y = curY;
						}
						else if ( StepType == StepType.ForwardStep ||
										StepType == StepType.ForwardSegment )
						{
							arrPoints[index].X = curX;
							arrPoints[index].Y = lastY;
							index++;
							arrPoints[index].X = curX;
							arrPoints[index].Y = curY;
						}
						else if ( StepType == StepType.RearwardStep ||
										StepType == StepType.RearwardSegment )
						{
							arrPoints[index].X = lastX;
							arrPoints[index].Y = curY;
							index++;
							arrPoints[index].X = curX;
							arrPoints[index].Y = curY;
						}

						lastX = curX;
						lastY = curY;
						index++;

					}

				}

				// Make sure there is at least one valid point
				if ( index == 0 )
					return false;

				// Add an extra point at the end, since the smoothing algorithm requires it
				arrPoints[index] = arrPoints[index - 1];
				index++;

				count = index;
				return true;
			}
		    return false;
		}