Esempio n. 1
0
		/// <summary>
		/// Template to make a line draw.
		/// </summary>
		/// <param name="g">Graphics context.</param>
		/// <param name="allLinePoints">The plot data. Don't use the Range property of the pdata, since it is overriden by the next argument.</param>
		/// <param name="range">The plot range to use.</param>
		/// <param name="layer">Graphics layer.</param>
		/// <param name="linePen">The pen to draw the line.</param>
		/// <param name="symbolGap">The size of the symbol gap. Argument is the original index of the data. The return value is the absolute symbol gap at this index.
		/// This function is null if no symbol gap is required.</param>
		/// <param name="skipFrequency">Skip frequency. Normally 1, thus all gaps are taken into account. If 2, only every 2nd gap is taken into account, and so on.</param>
		/// <param name="connectCircular">If true, there is a line connecting the start and the end of the range.</param>
		/// <param name="linePlotStyle">The line plot style.</param>
		public override void PaintOneRange(
			Graphics g,
			PointF[] allLinePoints,
			IPlotRange range,
			IPlotArea layer,
			PenX linePen,
			Func<int, double> symbolGap,
			int skipFrequency,
			bool connectCircular,
			LinePlotStyle linePlotStyle)
		{
			if (range.Length < 2)
				return;

			int lastIdx;
			int numberOfPointsPerOriginalPoint;
			PointF[] stepPolylinePoints = GetStepPolylinePoints(allLinePoints, range, layer, connectCircular, out numberOfPointsPerOriginalPoint, out lastIdx);

			GraphicsPath gp = new GraphicsPath();

			if (null != symbolGap)
			{
				int end = range.UpperBound - 1;

				var subPointsLength = skipFrequency * numberOfPointsPerOriginalPoint + 1;
				for (int i = 0; i < range.Length; i += skipFrequency)
				{

					int partialPolylineLength = Math.Min(subPointsLength, stepPolylinePoints.Length - numberOfPointsPerOriginalPoint * i);
					if (partialPolylineLength < 2)
						continue; // happens probably at the end of the range if there are not enough points to draw

					double gapAtStart = symbolGap(range.GetOriginalRowIndexFromPlotPointIndex(range.LowerBound + i));
					double gapAtEnd;
					if (connectCircular && skipFrequency >= (range.Length - i))
						gapAtEnd = symbolGap(range.OriginalFirstPoint);
					else if (skipFrequency <= (range.Length - 1 - i))
						gapAtEnd = symbolGap(range.GetOriginalRowIndexFromPlotPointIndex(range.LowerBound + i + skipFrequency));
					else
						gapAtEnd = 0;

					int startOfPartialPolyline = numberOfPointsPerOriginalPoint * i;
					var shortenedPolyline = stepPolylinePoints.ShortenPartialPolylineByDistanceFromStartAndEnd(startOfPartialPolyline, startOfPartialPolyline + partialPolylineLength - 1, gapAtStart / 2, gapAtEnd / 2);

					if (null != shortenedPolyline)
						g.DrawLines(linePen, shortenedPolyline);
				}
			}
			else
			{
				if (connectCircular)
					g.DrawPolygon(linePen, stepPolylinePoints);
				else
					g.DrawLines(linePen, stepPolylinePoints);
			}
		}
Esempio n. 2
0
 /// <summary>
 /// Template to make a line draw.
 /// </summary>
 /// <param name="g">Graphics context.</param>
 /// <param name="allLinePoints">The plot data. Don't use the Range property of the pdata, since it is overriden by the next argument.</param>
 /// <param name="range">The plot range to use.</param>
 /// <param name="layer">Graphics layer.</param>
 /// <param name="pen">The pen to draw the line.</param>
 /// <param name="symbolGap">The size of the symbol gap. Argument is the original index of the data. The return value is the absolute symbol gap at this index.
 /// This function is null if no symbol gap is required.</param>
 /// <param name="skipFrequency">Skip frequency. Normally 1, thus all gaps are taken into account. If 2, only every 2nd gap is taken into account, and so on.</param>
 /// <param name="connectCircular">If true, the line is connected circular, and the area is the polygon inside of that circular connection.</param>
 /// <param name="linePlotStyle">The line plot style.</param>
 public abstract void PaintOneRange(
     Graphics g,
     PointF[] allLinePoints,
     IPlotRange range,
     IPlotArea layer,
     PenX pen,
     Func <int, double> symbolGap,
     int skipFrequency,
     bool connectCircular,
     LinePlotStyle linePlotStyle
     );
Esempio n. 3
0
		/// <summary>
		/// Template to make a line draw.
		/// </summary>
		/// <param name="g">Graphics context.</param>
		/// <param name="allLinePoints">The plot data. Don't use the Range property of the pdata, since it is overriden by the next argument.</param>
		/// <param name="range">The plot range to use.</param>
		/// <param name="layer">Graphics layer.</param>
		/// <param name="pen">The pen to draw the line.</param>
		/// <param name="symbolGap">The size of the symbol gap. Argument is the original index of the data. The return value is the absolute symbol gap at this index.
		/// This function is null if no symbol gap is required.</param>
		/// <param name="skipFrequency">Skip frequency. Normally 1, thus all gaps are taken into account. If 2, only every 2nd gap is taken into account, and so on.</param>
		/// <param name="connectCircular">If true, the line is connected circular, and the area is the polygon inside of that circular connection.</param>
		/// <param name="linePlotStyle">The line plot style.</param>
		public abstract void PaintOneRange(
			Graphics g,
			PointF[] allLinePoints,
			IPlotRange range,
			IPlotArea layer,
			PenX pen,
			Func<int, double> symbolGap,
			int skipFrequency,
			bool connectCircular,
			LinePlotStyle linePlotStyle
);
        public XYPlotLineStyleController(LinePlotStyle doc)
        {
            if (doc == null)
            {
                throw new ArgumentNullException("doc is null");
            }

            if (!InitializeDocument(doc))
            {
                throw new ApplicationException("Programming error");
            }
        }
Esempio n. 5
0
 private void cmdOK_Click(object sender, EventArgs e)
 {
     if (cboScale.SelectedIndex > -1)
     {
         color        = pictureBoxColor.BackColor;
         scale        = double.Parse(cboScale.Items[cboScale.SelectedIndex].ToString());
         plotStyle    = (LinePlotStyle)cboPlotStyle.SelectedIndex;
         dashStyle    = (System.Drawing.Drawing2D.DashStyle)cboDashStyle.SelectedIndex;
         DialogResult = DialogResult.OK;
         Close();
     }
 }
Esempio n. 6
0
        public static G2DPlotStyleCollection PlotStyle_LineArea(Altaxo.Main.Properties.IReadOnlyPropertyBag context)
        {
            var result = new G2DPlotStyleCollection();
            var ps1    = new LinePlotStyle(context);
            var ps2    = new DropAreaPlotStyle(context)
            {
                FillDirection = Graph.CSPlaneID.Bottom
            };

            result.Add(ps1);
            result.Add(ps2);
            return(result);
        }
Esempio n. 7
0
        /// <summary>
        /// Template to make a line draw.
        /// </summary>
        /// <param name="g">Graphics context.</param>
        /// <param name="allLinePoints">The plot data. Don't use the Range property of the pdata, since it is overriden by the next argument.</param>
        /// <param name="range">The plot range to use.</param>
        /// <param name="layer">Graphics layer.</param>
        /// <param name="linePen">The pen to draw the line.</param>
        /// <param name="symbolGap">The size of the symbol gap. Argument is the original index of the data. The return value is the absolute symbol gap at this index.
        /// This function is null if no symbol gap is required.</param>
        /// <param name="skipFrequency">Skip frequency. Normally 1, thus all gaps are taken into account. If 2, only every 2nd gap is taken into account, and so on.</param>
        /// <param name="connectCircular">If true, there is a line connecting the start and the end of the range.</param>
        /// <param name="linePlotStyle">The line plot style.</param>
        public override void PaintOneRange(
            Graphics g,
            PointF[] allLinePoints,
            IPlotRange range,
            IPlotArea layer,
            PenX linePen,
            Func <int, double> symbolGap,
            int skipFrequency,
            bool connectCircular,
            LinePlotStyle linePlotStyle)
        {
            if (range.Length <= 1)
            {
                return; // seems to be only a single point, thus no connection possible
            }
            PointF[] stepPolylinePoints = GetStepPolylinePoints(allLinePoints, range, layer, connectCircular, out var numberOfPointsPerOriginalPoint, out var lastIdx);

            if (null != symbolGap)
            {
                foreach (var segmentRange in GetSegmentRanges(range, symbolGap, skipFrequency, connectCircular))
                {
                    if (segmentRange.IsFullRangeClosedCurve) // test if this is a closed polygon without any gaps -> draw a closed polygon and return
                    {
                        // use the whole circular arry to draw a closed polygon without any gaps
                        g.DrawPolygon(linePen, stepPolylinePoints);
                    }
                    else
                    {
                        int plotIndexAtStart  = segmentRange.IndexAtSubRangeStart * numberOfPointsPerOriginalPoint;
                        int plotIndexAtEnd    = segmentRange.IndexAtSubRangeEnd * numberOfPointsPerOriginalPoint;
                        var shortenedPolyline = stepPolylinePoints.ShortenPartialPolylineByDistanceFromStartAndEnd(plotIndexAtStart, plotIndexAtEnd, segmentRange.GapAtSubRangeStart / 2, segmentRange.GapAtSubRangeEnd / 2);

                        if (null != shortenedPolyline)
                        {
                            g.DrawLines(linePen, shortenedPolyline);
                        }
                    }
                }
            }
            else
            {
                if (connectCircular)
                {
                    g.DrawPolygon(linePen, stepPolylinePoints);
                }
                else
                {
                    g.DrawLines(linePen, stepPolylinePoints);
                }
            }
        }
        public bool InitializeDocument(params object[] args)
        {
            if (args.Length == 0 || !(args[0] is LinePlotStyle))
            {
                return(false);
            }

            bool isFirstTime = (null == _doc);

            _doc     = (LinePlotStyle)args[0];
            _tempDoc = _useDocumentCopy == UseDocument.Directly ? _doc : (LinePlotStyle)_doc.Clone();
            Initialize(isFirstTime);
            return(true);
        }
Esempio n. 9
0
        public ILine AddLine(string nameId, Color color, double scale, LinePlotStyle plotStyle, DashStyle dashStyle)
        {
            if (LineExists(nameId))
            {
                return(GetLine(nameId));
            }

            ILine line = new FlowLine(nameId, color, scale);

            line.Color     = color;
            line.Scale     = scale;
            line.PlotStyle = plotStyle;
            line.DashStyle = dashStyle;

            lines.Add(line);
            return(line);
        }
Esempio n. 10
0
        private void DrawLineMarker(ref Graphics g, Color lineColor, int x, int y, LinePlotStyle style)
        {
            using (Pen plotPen = new Pen(lineColor, 2))
            {
                switch (style)
                {
                case LinePlotStyle.Dots:
                    g.DrawEllipse(plotPen, x - 2, y - 2, 4, 4);
                    break;

                case LinePlotStyle.Cross:
                    g.DrawLine(plotPen, x, y - 3, x, y + 3);
                    g.DrawLine(plotPen, x - 3, y, x + 3, y);
                    break;

                case LinePlotStyle.Ex:
                    g.DrawLine(plotPen, x - 3, y - 3, x + 3, y + 3);
                    g.DrawLine(plotPen, x - 3, y + 3, x + 3, y - 3);
                    break;

                case LinePlotStyle.Box:
                    g.DrawLine(plotPen, x - 3, y - 3, x + 3, y - 3);
                    g.DrawLine(plotPen, x + 3, y - 3, x + 3, y + 3);
                    g.DrawLine(plotPen, x + 3, y + 3, x - 3, y + 3);
                    g.DrawLine(plotPen, x - 3, y + 3, x - 3, y - 3);
                    break;

                case LinePlotStyle.Triangle:
                    g.DrawLine(plotPen, x, y - 3, x + 3, y + 3);
                    g.DrawLine(plotPen, x + 3, y + 3, x - 3, y + 3);
                    g.DrawLine(plotPen, x - 3, y + 3, x, y - 3);
                    break;

                default:
                    break;
                }
            }
        }
Esempio n. 11
0
        /// <summary>
        /// Template to make a line draw.
        /// </summary>
        /// <param name="g">Graphics context.</param>
        /// <param name="allLinePoints">The plot data. Don't use the Range property of the pdata, since it is overriden by the next argument.</param>
        /// <param name="range">The plot range to use.</param>
        /// <param name="layer">Graphics layer.</param>
        /// <param name="linePen">The pen to draw the line.</param>
        /// <param name="symbolGap">The size of the symbol gap. Argument is the original index of the data. The return value is the absolute symbol gap at this index.
        /// This function is null if no symbol gap is required.</param>
        /// <param name="skipFrequency">Skip frequency. Normally 1, thus all gaps are taken into account. If 2, only every 2nd gap is taken into account, and so on.</param>
        /// <param name="connectCircular">If true, there is a line connecting the start and the end of the range.</param>
        /// <param name="linePlotStyle">The line plot style.</param>
        public override void PaintOneRange(
            Graphics g,
            PointF[] allLinePoints,
            IPlotRange range,
            IPlotArea layer,
            PenX linePen,
            Func <int, double> symbolGap,
            int skipFrequency,
            bool connectCircular,
            LinePlotStyle linePlotStyle)
        {
            // Bezier is only supported with point numbers n=4+3*k
            // so trim the range appropriately
            if (range.Length < 4)
            {
                return; // then too less points are in this range
            }
            PointF[] circularLinePoints;

            if (connectCircular)
            {
                var circularLinePointsLengthM1 = 2 + TrimToValidBezierLength(range.Length);
                circularLinePoints = new PointF[circularLinePointsLengthM1 + 1];
                Array.Copy(allLinePoints, range.LowerBound, circularLinePoints, 0, range.Length); // Extract
                circularLinePoints[circularLinePointsLengthM1] = circularLinePoints[0];

                // amend missing control points
                if (circularLinePointsLengthM1 - range.Length >= 1)
                {
                    circularLinePoints[circularLinePointsLengthM1 - 1] = GdiExtensionMethods.Interpolate(circularLinePoints[circularLinePointsLengthM1 - 3], circularLinePoints[circularLinePointsLengthM1], 0.5); // Last Control point should be halfway between
                }
                if (circularLinePointsLengthM1 - range.Length >= 2)
                {
                    circularLinePoints[circularLinePointsLengthM1 - 2] = GdiExtensionMethods.Interpolate(circularLinePoints[circularLinePointsLengthM1 - 3], circularLinePoints[circularLinePointsLengthM1], 0.5); // Middle Control point should be halfway between previous fixed point and last(=first) fixed point
                }
                range = range.WithUpperBoundExtendedBy(circularLinePointsLengthM1 - range.Length);
            }
            else // not circular
            {
                var trimmedLength = TrimToValidBezierLength(range.Length);
                if (range.Length != trimmedLength)
                {
                    range = range.WithUpperBoundShortenedBy(range.Length - trimmedLength);
                }

                if (range.LowerBound == 0 && trimmedLength == allLinePoints.Length)
                {
                    circularLinePoints = allLinePoints;
                }
                else
                {
                    circularLinePoints = new PointF[trimmedLength];
                    Array.Copy(allLinePoints, range.LowerBound, circularLinePoints, 0, trimmedLength); // Extract
                }
            }

            if (null != symbolGap)                                                                  // circular with symbol gap
            {
                var realSkipFrequency = skipFrequency % 3 == 0 ? skipFrequency : skipFrequency * 3; // least common multiple of skipFrequency and 3
                var skipLinePoints    = new PointF[0];
                foreach (var segmentRange in GetSegmentRanges(range, symbolGap, realSkipFrequency, connectCircular))
                {
                    if (segmentRange.IsFullRangeClosedCurve) // test if this is a closed polygon without any gaps -> draw a closed polygon and return
                    {
                        // use the whole circular arry to draw a closed polygon without any gaps
                        g.DrawBeziers(linePen, circularLinePoints);
                    }
                    else
                    {
                        var skipLinePointsLength = 1 + segmentRange.Length;
                        if (skipLinePoints.Length != skipLinePointsLength)
                        {
                            skipLinePoints = new PointF[skipLinePointsLength];
                        }
                        Array.Copy(circularLinePoints, segmentRange.IndexAtSubRangeStart, skipLinePoints, 0, skipLinePointsLength);

                        PointF[] shortenedLinePoints;
                        if (segmentRange.GapAtSubRangeStart != 0 || segmentRange.GapAtSubRangeEnd != 0)
                        {
                            shortenedLinePoints = GdiExtensionMethods.ShortenBezierCurve(skipLinePoints, segmentRange.GapAtSubRangeStart / 2, segmentRange.GapAtSubRangeEnd / 2);
                        }
                        else
                        {
                            shortenedLinePoints = skipLinePoints;
                        }

                        if (null != shortenedLinePoints)
                        {
                            g.DrawBeziers(linePen, shortenedLinePoints);
                        }
                    }
                }
            }
            else // no symbol gap
            {
                g.DrawBeziers(linePen, circularLinePoints);
            }
        }
Esempio n. 12
0
		/// <summary>
		/// Template to make a line draw.
		/// </summary>
		/// <param name="g">Graphics context.</param>
		/// <param name="allLinePoints">The plot data. Don't use the Range property of the pdata, since it is overriden by the next argument.</param>
		/// <param name="range">The plot range to use.</param>
		/// <param name="layer">Graphics layer.</param>
		/// <param name="linePen">The pen to draw the line.</param>
		/// <param name="symbolGap">The size of the symbol gap. Argument is the original index of the data. The return value is the absolute symbol gap at this index.
		/// This function is null if no symbol gap is required.</param>
		/// <param name="skipFrequency">Skip frequency. Normally 1, thus all gaps are taken into account. If 2, only every 2nd gap is taken into account, and so on.</param>
		/// <param name="connectCircular">If true, there is a line connecting the start and the end of the range.</param>
		/// <param name="linePlotStyle">The line plot style.</param>
		public override void PaintOneRange(
			Graphics g,
			PointF[] allLinePoints,
			IPlotRange range,
			IPlotArea layer,
			PenX linePen,
			Func<int, double> symbolGap,
			int skipFrequency,
			bool connectCircular,
			LinePlotStyle linePlotStyle)
		{
			int lastIdx;
			PointF[] subLinePoints = Segment2Connection_GetSubPoints(allLinePoints, range, layer, connectCircular, out lastIdx);

			GraphicsPath gp = new GraphicsPath();
			int i;

			// special efforts are necessary to realize a line/symbol gap
			// I decided to use a path for this
			// and hope that not so many segments are added to the path due
			// to the exclusion criteria that a line only appears between two symbols (rel<0.5)
			// if the symbols do not overlap. So for a big array of points it is very likely
			// that the symbols overlap and no line between the symbols needs to be plotted
			if (null != symbolGap)
			{
				float startx, starty, stopx, stopy;
				for (i = 0; i < lastIdx; i += 2)
				{

					var diff = GdiExtensionMethods.Subtract(subLinePoints[i + 1], subLinePoints[i]);
					var diffLength = GdiExtensionMethods.VectorLength(diff);

					int originalIndex = range.GetOriginalRowIndexFromPlotPointIndex(range.LowerBound + i);
					double gapAtStart = 0 == i % skipFrequency ? symbolGap(originalIndex) : 0;
					double gapAtEnd;
					if ((0 == (i + 1) % skipFrequency) || ((i + 1) == range.Length))
					{
						gapAtEnd = ((i + 1) != range.Length) ? symbolGap(originalIndex + 1) : symbolGap(range.GetOriginalRowIndexFromPlotPointIndex(range.LowerBound));
					}
					else
					{
						gapAtEnd = 0;
					}

					var relAtStart = (float)(0.5 * gapAtStart / diffLength); // 0.5 because symbolGap is the full gap between two lines, thus between the symbol center and the beginning of the line it is only 1/2
					var relAtEnd = (float)(0.5 * gapAtEnd / diffLength); // 0.5 because symbolGap is the full gap between two lines, thus between the symbol center and the beginning of the line it is only 1/2
					if ((relAtStart + relAtEnd) < 1) // a line only appears if sum of the gaps  is smaller than 1
					{
						startx = subLinePoints[i].X + relAtStart * diff.X;
						starty = subLinePoints[i].Y + relAtStart * diff.Y;
						stopx = subLinePoints[i + 1].X - relAtEnd * diff.X;
						stopy = subLinePoints[i + 1].Y - relAtEnd * diff.Y;

						gp.AddLine(startx, starty, stopx, stopy);
						gp.StartFigure();
					}
				} // end for
				g.DrawPath(linePen, gp);
				gp.Reset();
			}
			else // no line symbol gap required, so we can use DrawLines to draw the lines
			{
				for (i = 0; i < lastIdx; i += 2)
				{
					gp.AddLine(subLinePoints[i].X, subLinePoints[i].Y, subLinePoints[i + 1].X, subLinePoints[i + 1].Y);
					gp.StartFigure();
				} // end for
				g.DrawPath(linePen, gp);
				gp.Reset();
			}
		}
Esempio n. 13
0
        /// <summary>
        /// Template to make a line draw.
        /// </summary>
        /// <param name="g">Graphics context.</param>
        /// <param name="allLinePoints">The plot data. Don't use the Range property of the pdata, since it is overriden by the next argument.</param>
        /// <param name="range">The plot range to use.</param>
        /// <param name="layer">Graphics layer.</param>
        /// <param name="linePen">The pen to draw the line.</param>
        /// <param name="symbolGap">The size of the symbol gap. Argument is the original index of the data. The return value is the absolute symbol gap at this index.
        /// This function is null if no symbol gap is required.</param>
        /// <param name="skipFrequency">Skip frequency. Normally 1, thus all gaps are taken into account. If 2, only every 2nd gap is taken into account, and so on.</param>
        /// <param name="connectCircular">If true, there is a line connecting the start and the end of the range.</param>
        /// <param name="linePlotStyle">The line plot style.</param>
        public override void PaintOneRange(
            Graphics g,
            PointF[] allLinePoints,
            IPlotRange range,
            IPlotArea layer,
            PenX linePen,
            Func <int, double> symbolGap,
            int skipFrequency,
            bool connectCircular,
            LinePlotStyle linePlotStyle)
        {
            PointF[] subLinePoints;
            if (range.LowerBound == 0 && range.UpperBound == allLinePoints.Length)
            {
                // under optimal conditions we can use allLinePoints directly
                subLinePoints = allLinePoints;
            }
            else
            {
                // otherwise, make a new array
                subLinePoints = new PointF[range.Length];
                Array.Copy(allLinePoints, range.LowerBound, subLinePoints, 0, range.Length); // Extract
            }

            int lastIdx   = range.Length - 1;
            var layerSize = layer.Size;

            if (connectCircular)
            {
                if (null != symbolGap)
                {
                    // convert points to bezier segments
                    var bezierSegments    = GdiExtensionMethods.ClosedCardinalSplineToBezierSegments(subLinePoints, subLinePoints.Length);
                    var subBezierSegments = new PointF[0];
                    foreach (var segmentRange in GetSegmentRanges(range, symbolGap, skipFrequency, connectCircular))
                    {
                        if (segmentRange.IsFullRangeClosedCurve) // test if this is a closed polygon without any gaps -> draw a closed polygon and return
                        {
                            // use the whole circular arry to draw a closed polygon without any gaps
                            g.DrawClosedCurve(linePen, subLinePoints);
                        }
                        else
                        {
                            var subBezierLength = 3 * segmentRange.Length + 1;
                            if (subBezierSegments.Length != subBezierLength)
                            {
                                subBezierSegments = new PointF[subBezierLength];
                            }

                            Array.Copy(bezierSegments, segmentRange.IndexAtSubRangeStart * 3, subBezierSegments, 0, subBezierLength);
                            var shortenedBezierSegments = GdiExtensionMethods.ShortenBezierCurve(subBezierSegments, segmentRange.GapAtSubRangeStart / 2, segmentRange.GapAtSubRangeEnd / 2);

                            if (null != shortenedBezierSegments)
                            {
                                g.DrawBeziers(linePen, shortenedBezierSegments);
                            }
                        }
                    }
                }
                else
                {
                    g.DrawClosedCurve(linePen, subLinePoints);
                }
            }
            else // not circular
            {
                if (symbolGap != null)
                {
                    // convert points to bezier segments
                    var bezierSegments    = GdiExtensionMethods.OpenCardinalSplineToBezierSegments(subLinePoints, subLinePoints.Length);
                    var subBezierSegments = new PointF[0];

                    foreach (var segmentRange in GetSegmentRanges(range, symbolGap, skipFrequency, connectCircular))
                    {
                        if (segmentRange.IsFullRangeClosedCurve) // test if this is a closed polygon without any gaps -> draw a closed polygon and return
                        {
                            // use the whole circular arry to draw a closed polygon without any gaps
                            g.DrawCurve(linePen, subLinePoints);
                        }
                        else
                        {
                            var subBezierLength = 3 * segmentRange.Length + 1;
                            if (subBezierSegments.Length != subBezierLength)
                            {
                                subBezierSegments = new PointF[subBezierLength];
                            }

                            Array.Copy(bezierSegments, segmentRange.IndexAtSubRangeStart * 3, subBezierSegments, 0, subBezierLength);
                            var shortenedBezierSegments = GdiExtensionMethods.ShortenBezierCurve(subBezierSegments, segmentRange.GapAtSubRangeStart / 2, segmentRange.GapAtSubRangeEnd / 2);

                            if (null != shortenedBezierSegments)
                            {
                                g.DrawBeziers(linePen, shortenedBezierSegments);
                            }
                        }
                    }
                }
                else
                {
                    g.DrawCurve(linePen, subLinePoints);
                }
            }
        }
Esempio n. 14
0
		/// <summary>
		/// Template to make a line draw.
		/// </summary>
		/// <param name="g">Graphics context.</param>
		/// <param name="allLinePoints">The plot data. Don't use the Range property of the pdata, since it is overriden by the next argument.</param>
		/// <param name="range">The plot range to use.</param>
		/// <param name="layer">Graphics layer.</param>
		/// <param name="linePen">The pen to draw the line.</param>
		/// <param name="symbolGap">The size of the symbol gap. Argument is the original index of the data. The return value is the absolute symbol gap at this index.
		/// This function is null if no symbol gap is required.</param>
		/// <param name="skipFrequency">Skip frequency. Normally 1, thus all gaps are taken into account. If 2, only every 2nd gap is taken into account, and so on.</param>
		/// <param name="connectCircular">If true, there is a line connecting the start and the end of the range.</param>
		/// <param name="linePlotStyle">The line plot style.</param>
		public override void PaintOneRange(
			Graphics g,
			PointF[] allLinePoints,
			IPlotRange range,
			IPlotArea layer,
			PenX linePen,
			Func<int, double> symbolGap,
			int skipFrequency,
			bool connectCircular,
			LinePlotStyle linePlotStyle)
		{
			PointF[] circularLinePoints;

			if (!connectCircular && range.LowerBound == 0 && range.UpperBound == allLinePoints.Length)
			{
				// under optimal conditions we can use allLinePoints directly
				circularLinePoints = allLinePoints;
			}
			else
			{
				// otherwise, make a new array
				circularLinePoints = new PointF[range.Length + (connectCircular ? 1 : 0)];
				Array.Copy(allLinePoints, range.LowerBound, circularLinePoints, 0, range.Length); // Extract
				if (connectCircular)
					circularLinePoints[circularLinePoints.Length - 1] = circularLinePoints[0];
			}

			int lastIdx = range.Length - 1 + (connectCircular ? 1 : 0);
			GraphicsPath gp = new GraphicsPath();
			var layerSize = layer.Size;
			var rangeLowerBound = range.LowerBound;

			// special efforts are necessary to realize a line/symbol gap
			// I decided to use a path for this
			// and hope that not so many segments are added to the path due
			// to the exclusion criteria that a line only appears between two symbols (rel<0.5)
			// if the symbols do not overlap. So for a big array of points it is very likely
			// that the symbols overlap and no line between the symbols needs to be plotted
			if (null != symbolGap)
			{
				float xdiff, ydiff, startx, starty, stopx, stopy;
				if (skipFrequency <= 1) // skip all scatter symbol gaps -> thus skipOffset can be ignored
				{
					for (int i = 0; i < lastIdx; i++)
					{
						xdiff = circularLinePoints[i + 1].X - circularLinePoints[i].X;
						ydiff = circularLinePoints[i + 1].Y - circularLinePoints[i].Y;
						var diffLength = System.Math.Sqrt(xdiff * xdiff + ydiff * ydiff);
						double gapAtStart = symbolGap(range.GetOriginalRowIndexFromPlotPointIndex(range.LowerBound + i));
						double gapAtEnd;
						if (connectCircular && skipFrequency >= (range.Length - i))
							gapAtEnd = symbolGap(range.OriginalFirstPoint);
						else if (skipFrequency <= (range.Length - 1 - i))
							gapAtEnd = symbolGap(range.GetOriginalRowIndexFromPlotPointIndex(range.LowerBound + i + skipFrequency));
						else
							gapAtEnd = 0;

						var relAtStart = (float)(0.5 * gapAtStart / diffLength); // 0.5 because symbolGap is the full gap between two lines, thus between the symbol center and the beginning of the line it is only 1/2
						var relAtEnd = (float)(0.5 * gapAtEnd / diffLength); // 0.5 because symbolGap is the full gap between two lines, thus between the symbol center and the beginning of the line it is only 1/2

						if ((relAtStart + relAtEnd) < 1) // a line only appears if sum of the gaps  is smaller than 1
						{
							startx = circularLinePoints[i].X + relAtStart * xdiff;
							starty = circularLinePoints[i].Y + relAtStart * ydiff;
							stopx = circularLinePoints[i + 1].X - relAtEnd * xdiff;
							stopy = circularLinePoints[i + 1].Y - relAtEnd * ydiff;

							gp.AddLine(startx, starty, stopx, stopy);
							gp.StartFigure();
						}
					} // end for
					g.DrawPath(linePen, gp);
					gp.Reset();
				}
				else // skipFrequency is > 1
				{
					for (int i = 0; i < lastIdx; i += skipFrequency)
					{
						int subPointLengthM1 = Math.Min(skipFrequency, circularLinePoints.Length - 1 - i);
						double gapAtStart = symbolGap(range.GetOriginalRowIndexFromPlotPointIndex(range.LowerBound + i));
						double gapAtEnd;
						if (connectCircular && skipFrequency >= (range.Length - i))
							gapAtEnd = symbolGap(range.OriginalFirstPoint);
						else if (skipFrequency <= (range.Length - 1 - i))
							gapAtEnd = symbolGap(range.GetOriginalRowIndexFromPlotPointIndex(range.LowerBound + i + skipFrequency));
						else
							gapAtEnd = 0;

						if (subPointLengthM1 >= 1)
						{
							var polyline = circularLinePoints.ShortenPartialPolylineByDistanceFromStartAndEnd(i, i + subPointLengthM1, gapAtStart / 2, gapAtEnd / 2);

							if (null != polyline)
								g.DrawLines(linePen, polyline);
						}
					} // end for
				}
			}
			else // no line symbol gap required, so we can use DrawLines to draw the lines
			{
				if (circularLinePoints.Length > 1) // we don't want to have a drawing exception if number of points is only one
				{
					g.DrawLines(linePen, circularLinePoints);
				}
			}
		}
Esempio n. 15
0
        /// <summary>
        /// Template to make a line draw.
        /// </summary>
        /// <param name="g">Graphics context.</param>
        /// <param name="allLinePoints">The plot data. Don't use the Range property of the pdata, since it is overriden by the next argument.</param>
        /// <param name="range">The plot range to use.</param>
        /// <param name="layer">Graphics layer.</param>
        /// <param name="linePen">The pen to draw the line.</param>
        /// <param name="symbolGap">The size of the symbol gap. Argument is the original index of the data. The return value is the absolute symbol gap at this index.
        /// This function is null if no symbol gap is required.</param>
        /// <param name="skipFrequency">Skip frequency. Normally 1, thus all gaps are taken into account. If 2, only every 2nd gap is taken into account, and so on.</param>
        /// <param name="connectCircular">If true, there is a line connecting the start and the end of the range.</param>
        /// <param name="linePlotStyle">The line plot style.</param>
        public override void PaintOneRange(
            Graphics g,
            PointF[] allLinePoints,
            IPlotRange range,
            IPlotArea layer,
            PenX linePen,
            Func <int, double> symbolGap,
            int skipFrequency,
            bool connectCircular,
            LinePlotStyle linePlotStyle)
        {
            if (range.Length <= 1)
            {
                return; // seems to be only a single point, thus no connection possible
            }
            PointF[] circularLinePoints;
            int      indexBasePlotPoints; // index of the first plot point of this range in circularLinePoints array

            if (connectCircular)          // we have to copy the array in order to append the first point to the end
            {
                // otherwise, make a new array
                circularLinePoints = new PointF[range.Length + 1];
                Array.Copy(allLinePoints, range.LowerBound, circularLinePoints, 0, range.Length); // Extract
                circularLinePoints[circularLinePoints.Length - 1] = circularLinePoints[0];
                indexBasePlotPoints = 0;
            }
            else // use the array directly without copying
            {
                circularLinePoints  = allLinePoints;
                indexBasePlotPoints = range.LowerBound;
            }

            if (null != symbolGap)
            {
                foreach (var segmentRange in GetSegmentRanges(range, symbolGap, skipFrequency, connectCircular))
                {
                    if (segmentRange.IsFullRangeClosedCurve) // test if this is a closed polygon without any gaps -> draw a closed polygon and return
                    {
                        // use the whole circular arry to draw a closed polygon without any gaps
                        g.DrawPolygon(linePen, circularLinePoints);
                    }
                    else if (segmentRange.Length == 1) // special case only one line segment
                    {
                        int plotIndexAtStart = segmentRange.IndexAtSubRangeStart + indexBasePlotPoints;
                        int plotIndexAtEnd   = segmentRange.IndexAtSubRangeEnd + indexBasePlotPoints;

                        var xdiff      = circularLinePoints[plotIndexAtEnd].X - circularLinePoints[plotIndexAtStart].X;
                        var ydiff      = circularLinePoints[plotIndexAtEnd].Y - circularLinePoints[plotIndexAtStart].Y;
                        var diffLength = System.Math.Sqrt(xdiff * xdiff + ydiff * ydiff);

                        var relAtStart = (float)(0.5 * segmentRange.GapAtSubRangeStart / diffLength); // 0.5 because symbolGap is the full gap between two lines, thus between the symbol center and the beginning of the line it is only 1/2
                        var relAtEnd   = (float)(0.5 * segmentRange.GapAtSubRangeEnd / diffLength);   // 0.5 because symbolGap is the full gap between two lines, thus between the symbol center and the beginning of the line it is only 1/2

                        if ((relAtStart + relAtEnd) < 1)                                              // a line only appears if sum of the gaps  is smaller than 1
                        {
                            var startx = circularLinePoints[plotIndexAtStart].X + relAtStart * xdiff;
                            var starty = circularLinePoints[plotIndexAtStart].Y + relAtStart * ydiff;
                            var stopx  = circularLinePoints[plotIndexAtEnd].X - relAtEnd * xdiff;
                            var stopy  = circularLinePoints[plotIndexAtEnd].Y - relAtEnd * ydiff;

                            g.DrawLine(linePen, startx, starty, stopx, stopy);
                        }
                    }
                    else
                    {
                        int plotIndexAtStart  = segmentRange.IndexAtSubRangeStart + indexBasePlotPoints;
                        int plotIndexAtEnd    = segmentRange.IndexAtSubRangeEnd + indexBasePlotPoints;
                        var shortenedPolyline = circularLinePoints.ShortenPartialPolylineByDistanceFromStartAndEnd(plotIndexAtStart, plotIndexAtEnd, segmentRange.GapAtSubRangeStart / 2, segmentRange.GapAtSubRangeEnd / 2);

                        if (null != shortenedPolyline)
                        {
                            g.DrawLines(linePen, shortenedPolyline);
                        }
                    }
                } // end for
            }
            else  // no line symbol gap required, so we can use DrawLines or DrawPolygon to draw the lines
            {
                if (connectCircular) // array was already copied from original array
                {
                    g.DrawPolygon(linePen, circularLinePoints);
                }
                else if (indexBasePlotPoints == 0 && range.Length == circularLinePoints.Length) // can use original array directly
                {
                    g.DrawLines(linePen, circularLinePoints);
                }
                else
                {
                    circularLinePoints = new PointF[range.Length];
                    Array.Copy(allLinePoints, range.LowerBound, circularLinePoints, 0, range.Length);
                    g.DrawLines(linePen, circularLinePoints);
                }
            }
        }
Esempio n. 16
0
		/// <summary>
		/// Template to make a line draw.
		/// </summary>
		/// <param name="g">Graphics context.</param>
		/// <param name="allLinePoints">The plot data. Don't use the Range property of the pdata, since it is overriden by the next argument.</param>
		/// <param name="range">The plot range to use.</param>
		/// <param name="layer">Graphics layer.</param>
		/// <param name="linePen">The pen to draw the line.</param>
		/// <param name="symbolGap">The size of the symbol gap. Argument is the original index of the data. The return value is the absolute symbol gap at this index.
		/// This function is null if no symbol gap is required.</param>
		/// <param name="skipFrequency">Skip frequency. Normally 1, thus all gaps are taken into account. If 2, only every 2nd gap is taken into account, and so on.</param>
		/// <param name="connectCircular">If true, there is a line connecting the start and the end of the range.</param>
		/// <param name="linePlotStyle">The line plot style.</param>
		public override void PaintOneRange(
			Graphics g,
			PointF[] allLinePoints,
			IPlotRange range,
			IPlotArea layer,
			PenX linePen,
			Func<int, double> symbolGap,
			int skipFrequency,
			bool connectCircular,
			LinePlotStyle linePlotStyle)
		{
			PointF[] subLinePoints;
			if (range.LowerBound == 0 && range.UpperBound == allLinePoints.Length)
			{
				// under optimal conditions we can use allLinePoints directly
				subLinePoints = allLinePoints;
			}
			else
			{
				// otherwise, make a new array
				subLinePoints = new PointF[range.Length];
				Array.Copy(allLinePoints, range.LowerBound, subLinePoints, 0, range.Length); // Extract
			}

			int lastIdx = range.Length - 1;
			var layerSize = layer.Size;

			if (connectCircular)
			{
				if (symbolGap != null)
				{
					// convert points to bezier segments
					var bezierSegments = GdiExtensionMethods.ClosedCardinalSplineToBezierSegments(subLinePoints, subLinePoints.Length);
					var subBezierSegments = new PointF[0];
					int subPointLengthM1, subBezierLength;
					for (int i = 0; i < (range.Length); i += skipFrequency)
					{
						subPointLengthM1 = Math.Min(skipFrequency, range.Length - i);
						int originalIndexAtStart = range.GetOriginalRowIndexFromPlotPointIndex(i + range.LowerBound);
						double gapAtStart = symbolGap(originalIndexAtStart);
						int originalIndexAtEnd = ((i + skipFrequency) < range.Length) ? range.GetOriginalRowIndexFromPlotPointIndex(i + range.LowerBound + skipFrequency) : range.OriginalFirstPoint;
						double gapAtEnd = symbolGap(originalIndexAtEnd);
						subBezierLength = 3 * subPointLengthM1 + 1;
						if (subBezierSegments.Length != subBezierLength)
							subBezierSegments = new PointF[subBezierLength];

						Array.Copy(bezierSegments, i * 3, subBezierSegments, 0, subBezierLength);
						var shortenedBezierSegments = GdiExtensionMethods.ShortenBezierCurve(subBezierSegments, gapAtStart / 2, gapAtEnd / 2);

						if (null != shortenedBezierSegments)
						{
							g.DrawBeziers(linePen, shortenedBezierSegments);
						}
					}
				}
				else
				{
					g.DrawClosedCurve(linePen, subLinePoints);
				}
			}
			else
			{
				if (symbolGap != null)
				{
					// convert points to bezier segments
					var bezierSegments = GdiExtensionMethods.OpenCardinalSplineToBezierSegments(subLinePoints, subLinePoints.Length);
					var subBezierSegments = new PointF[0];
					int subPointLengthM1, subBezierLength;
					for (int i = 0; i < (range.Length - 1); i += skipFrequency)
					{
						subPointLengthM1 = Math.Min(skipFrequency, range.Length - 1 - i);
						int originalIndex = range.GetOriginalRowIndexFromPlotPointIndex(i + range.LowerBound);
						double gapAtStart = symbolGap(originalIndex);
						double gapAtEnd = subPointLengthM1 == skipFrequency ? symbolGap(range.GetOriginalRowIndexFromPlotPointIndex(i + range.LowerBound + skipFrequency)) : 0;
						subBezierLength = 3 * subPointLengthM1 + 1;
						if (subBezierSegments.Length != subBezierLength)
							subBezierSegments = new PointF[subBezierLength];

						Array.Copy(bezierSegments, i * 3, subBezierSegments, 0, subBezierLength);
						var shortenedBezierSegments = GdiExtensionMethods.ShortenBezierCurve(subBezierSegments, gapAtStart / 2, gapAtEnd / 2);

						if (null != shortenedBezierSegments)
						{
							g.DrawBeziers(linePen, shortenedBezierSegments);
						}
					}
				}
				else
				{
					g.DrawCurve(linePen, subLinePoints);
				}
			}
		}
Esempio n. 17
0
        /// <summary>
        /// Template to make a line draw.
        /// </summary>
        /// <param name="g">Graphics context.</param>
        /// <param name="allLinePoints">The plot data. Don't use the Range property of the pdata, since it is overriden by the next argument.</param>
        /// <param name="range">The plot range to use.</param>
        /// <param name="layer">Graphics layer.</param>
        /// <param name="linePen">The pen to draw the line.</param>
        /// <param name="symbolGap">The size of the symbol gap. Argument is the original index of the data. The return value is the absolute symbol gap at this index.
        /// This function is null if no symbol gap is required.</param>
        /// <param name="skipFrequency">Skip frequency. Normally 1, thus all gaps are taken into account. If 2, only every 2nd gap is taken into account, and so on.</param>
        /// <param name="connectCircular">If true, there is a line connecting the start and the end of the range.</param>
        /// <param name="linePlotStyle">The line plot style.</param>
        public override void PaintOneRange(
            Graphics g,
            PointF[] allLinePoints,
            IPlotRange range,
            IPlotArea layer,
            PenX linePen,
            Func <int, double> symbolGap,
            int skipFrequency,
            bool connectCircular,
            LinePlotStyle linePlotStyle)
        {
            PointF[] subLinePoints = Segment2Connection_GetSubPoints(allLinePoints, range, layer, connectCircular, out var lastIdx);

            var gp = new GraphicsPath();
            int i;

            // special efforts are necessary to realize a line/symbol gap
            // I decided to use a path for this
            // and hope that not so many segments are added to the path due
            // to the exclusion criteria that a line only appears between two symbols (rel<0.5)
            // if the symbols do not overlap. So for a big array of points it is very likely
            // that the symbols overlap and no line between the symbols needs to be plotted
            if (null != symbolGap)
            {
                float startx, starty, stopx, stopy;
                for (i = 0; i < lastIdx; i += 2)
                {
                    var diff       = GdiExtensionMethods.Subtract(subLinePoints[i + 1], subLinePoints[i]);
                    var diffLength = GdiExtensionMethods.VectorLength(diff);

                    int    originalIndex = range.GetOriginalRowIndexFromPlotPointIndex(range.LowerBound + i);
                    double gapAtStart    = 0 == i % skipFrequency ? symbolGap(originalIndex) : 0;
                    double gapAtEnd;
                    if ((0 == (i + 1) % skipFrequency) || ((i + 1) == range.Length))
                    {
                        gapAtEnd = ((i + 1) != range.Length) ? symbolGap(originalIndex + 1) : symbolGap(range.GetOriginalRowIndexFromPlotPointIndex(range.LowerBound));
                    }
                    else
                    {
                        gapAtEnd = 0;
                    }

                    var relAtStart = (float)(0.5 * gapAtStart / diffLength); // 0.5 because symbolGap is the full gap between two lines, thus between the symbol center and the beginning of the line it is only 1/2
                    var relAtEnd   = (float)(0.5 * gapAtEnd / diffLength);   // 0.5 because symbolGap is the full gap between two lines, thus between the symbol center and the beginning of the line it is only 1/2
                    if ((relAtStart + relAtEnd) < 1)                         // a line only appears if sum of the gaps  is smaller than 1
                    {
                        startx = subLinePoints[i].X + relAtStart * diff.X;
                        starty = subLinePoints[i].Y + relAtStart * diff.Y;
                        stopx  = subLinePoints[i + 1].X - relAtEnd * diff.X;
                        stopy  = subLinePoints[i + 1].Y - relAtEnd * diff.Y;

                        gp.AddLine(startx, starty, stopx, stopy);
                        gp.StartFigure();
                    }
                } // end for
                g.DrawPath(linePen, gp);
                gp.Reset();
            }
            else // no line symbol gap required, so we can use DrawLines to draw the lines
            {
                for (i = 0; i < lastIdx; i += 2)
                {
                    gp.AddLine(subLinePoints[i].X, subLinePoints[i].Y, subLinePoints[i + 1].X, subLinePoints[i + 1].Y);
                    gp.StartFigure();
                } // end for
                g.DrawPath(linePen, gp);
                gp.Reset();
            }
        }
Esempio n. 18
0
        void InitializeStyles()
        {
            // Clear the previous controller cache
            _additionalPlotStyle = null;
            if (_combinedScatterLineGroupController != null)
            {
                _combinedScatterLineGroupController.ChildControlChanged -= EhView_ActiveChildControlChanged;
                _combinedScatterLineGroupController = null;
            }
            _styleControllerList.Clear();


            // start to create new controllers
            if (_tempdoc.Style.Count > 0)
            {
                bool addHelperStyle = NeedsHelperStyle();
                bool useCombinedTab = UseCombinedScatterLineGroupTab();


                if (useCombinedTab)
                {
                    List <ControlViewElement> combList = new List <ControlViewElement>();

                    // create the controllers
                    IMVCANController ct1 = GetStyleController(_tempdoc.Style[0]);
                    _styleControllerList.Add(ct1);


                    if (addHelperStyle)
                    {
                        IPlotArea layer = Main.DocumentPath.GetRootNodeImplementing <IPlotArea>(_doc);
                        // add either line or scatter
                        if (_tempdoc.Style[0] is LinePlotStyle)
                        {
                            ScatterPlotStyle scatterStyle = new ScatterPlotStyle();
                            scatterStyle.ParentObject = _tempdoc.Style;
                            _tempdoc.Style.PrepareNewSubStyle(scatterStyle, layer, _doc.GetRangesAndPoints(layer));
                            _additionalPlotStyle = scatterStyle;
                            scatterStyle.Shape   = Altaxo.Graph.Gdi.Plot.Styles.XYPlotScatterStyles.Shape.NoSymbol;

                            _additionalPlotStyleController = GetStyleController(_additionalPlotStyle);
                            combList.Add(new ControlViewElement("Symbol", _additionalPlotStyleController));
                            combList.Add(new ControlViewElement("Line", ct1));
                        }
                        else
                        {
                            LinePlotStyle lineStyle = new LinePlotStyle();
                            lineStyle.ParentObject = _tempdoc.Style;
                            _tempdoc.Style.PrepareNewSubStyle(lineStyle, layer, _doc.GetRangesAndPoints(layer));
                            _additionalPlotStyle = lineStyle;
                            lineStyle.Connection = Altaxo.Graph.Gdi.Plot.Styles.XYPlotLineStyles.ConnectionStyle.NoLine;

                            _additionalPlotStyleController = GetStyleController(_additionalPlotStyle);
                            combList.Add(new ControlViewElement("Symbol", ct1));
                            combList.Add(new ControlViewElement("Line", _additionalPlotStyleController));
                        }
                    }
                    else // no helper style, i.e. second style is line style
                    {
                        // create the controllers
                        IMVCANController ct2 = GetStyleController(_tempdoc.Style[1]);
                        _styleControllerList.Add(ct2);
                        combList.Add(new ControlViewElement("Symbol", ct1));
                        combList.Add(new ControlViewElement("Line", ct2));
                    }

                    combList.Add(new ControlViewElement(string.Empty, this, this._plotGroupView));
                    _combinedScatterLineGroupController = new Common.MultiChildController(combList.ToArray(), true);
                    Current.Gui.FindAndAttachControlTo(_combinedScatterLineGroupController);
                    string title;
                    if (null != _additionalPlotStyle)
                    {
                        title = string.Format("#{0}:{1}", 1, Current.Gui.GetUserFriendlyClassName(_tempdoc.Style[0].GetType()));
                    }
                    else
                    {
                        title = "#1&&2:Symbol&&Line";
                    }
                    AddTab(title, _combinedScatterLineGroupController, _combinedScatterLineGroupController.ViewObject);
                    _combinedScatterLineGroupController.ChildControlChanged += this.EhView_ActiveChildControlChanged;
                } // if use CombinedTab

                // now the remaining styles
                int start = useCombinedTab ? (addHelperStyle ? 1 : 2) : 0;
                for (int i = start; i < _tempdoc.Style.Count; i++)
                {
                    IMVCANController ctrl = GetStyleController(_tempdoc.Style[i]);
                    _styleControllerList.Add(ctrl);
                    string title = string.Format("#{0}:{1}", (i + 1), Current.Gui.GetUserFriendlyClassName(_tempdoc.Style[i].GetType()));
                    AddTab(title, ctrl, ctrl != null ? ctrl.ViewObject : null);
                }
            }
            base.SetElements(false);
        }
Esempio n. 19
0
		/// <summary>
		/// Template to make a line draw.
		/// </summary>
		/// <param name="g">Graphics context.</param>
		/// <param name="allLinePoints">The plot data. Don't use the Range property of the pdata, since it is overriden by the next argument.</param>
		/// <param name="range">The plot range to use.</param>
		/// <param name="layer">Graphics layer.</param>
		/// <param name="linePen">The pen to draw the line.</param>
		/// <param name="symbolGap">The size of the symbol gap. Argument is the original index of the data. The return value is the absolute symbol gap at this index.
		/// This function is null if no symbol gap is required.</param>
		/// <param name="skipFrequency">Skip frequency. Normally 1, thus all gaps are taken into account. If 2, only every 2nd gap is taken into account, and so on.</param>
		/// <param name="connectCircular">If true, there is a line connecting the start and the end of the range.</param>
		/// <param name="linePlotStyle">The line plot style.</param>
		public override void PaintOneRange(
			Graphics g,
			PointF[] allLinePoints,
			IPlotRange range,
			IPlotArea layer,
			PenX linePen,
			Func<int, double> symbolGap,
			int skipFrequency,
			bool connectCircular,
			LinePlotStyle linePlotStyle)
		{
			// Bezier is only supported with point numbers n=4+3*k
			// so trim the range appropriately
			if (range.Length < 4)
				return; // then too less points are in this range

			if (connectCircular)
			{
				var circularLinePointsLengthM1 = 2 + TrimToValidBezierLength(range.Length);
				var circularLinePoints = new PointF[circularLinePointsLengthM1 + 1];
				Array.Copy(allLinePoints, range.LowerBound, circularLinePoints, 0, range.Length); // Extract
				circularLinePoints[circularLinePointsLengthM1] = circularLinePoints[0];

				// amend missing control points
				if (circularLinePointsLengthM1 - range.Length >= 1)
					circularLinePoints[circularLinePointsLengthM1 - 1] = GdiExtensionMethods.Interpolate(circularLinePoints[circularLinePointsLengthM1 - 3], circularLinePoints[circularLinePointsLengthM1], 0.5); // Last Control point should be halfway between
				if (circularLinePointsLengthM1 - range.Length >= 2)
					circularLinePoints[circularLinePointsLengthM1 - 2] = GdiExtensionMethods.Interpolate(circularLinePoints[circularLinePointsLengthM1 - 3], circularLinePoints[circularLinePointsLengthM1], 0.5); // Middle Control point should be halfway between previous fixed point and last(=first) fixed point

				if (null != symbolGap) // circular with symbol gap
				{
					var realSkipFrequency = skipFrequency % 3 == 0 ? skipFrequency : skipFrequency * 3; // least common multiple of skipFrequency and 3
					for (int i = 0; i < range.Length; i += realSkipFrequency)
					{
						var skipLinePointsLength = Math.Min(realSkipFrequency + 1, TrimToValidBezierLength(circularLinePoints.Length - i));
						if (skipLinePointsLength >= 4)
						{
							var skipLinePoints = new PointF[skipLinePointsLength];
							Array.Copy(circularLinePoints, i, skipLinePoints, 0, skipLinePointsLength); // Extract

							var gapAtStart = symbolGap(range.GetOriginalRowIndexFromPlotPointIndex(range.LowerBound + i));
							double gapAtEnd;
							if (connectCircular && realSkipFrequency >= (range.Length - 1 - i))
								gapAtEnd = symbolGap(range.OriginalFirstPoint);
							else if (realSkipFrequency <= (range.Length - 1 - i))
								gapAtEnd = symbolGap(range.GetOriginalRowIndexFromPlotPointIndex(range.LowerBound + i + realSkipFrequency));
							else
								gapAtEnd = 0;

							if (gapAtStart != 0 || gapAtEnd != 0)
							{
								skipLinePoints = GdiExtensionMethods.ShortenBezierCurve(skipLinePoints, gapAtStart / 2, gapAtEnd / 2);
							}

							if (null != skipLinePoints)
							{
								g.DrawBeziers(linePen, skipLinePoints);
							}
						}
					}
				}
				else // circular without symbol gap
				{
					g.DrawBeziers(linePen, circularLinePoints);
				}
			}
			else // not circular
			{
				if (null != symbolGap) // not circular with symbol gap
				{
					var realSkipFrequency = skipFrequency % 3 == 0 ? skipFrequency : skipFrequency * 3; // least common multiple of skipFrequency and 3
					for (int i = 0; i < range.Length; i += realSkipFrequency)
					{
						var skipLinePointsLength = Math.Min(realSkipFrequency + 1, TrimToValidBezierLength(range.Length - i));
						if (skipLinePointsLength >= 4)
						{
							var skipLinePoints = new PointF[skipLinePointsLength];
							Array.Copy(allLinePoints, range.LowerBound + i, skipLinePoints, 0, skipLinePointsLength); // Extract

							var gapAtStart = symbolGap(range.GetOriginalRowIndexFromPlotPointIndex(range.LowerBound + i));
							var gapAtEnd = symbolGap(range.GetOriginalRowIndexFromPlotPointIndex(range.LowerBound + i + skipLinePointsLength - 1));

							if (gapAtStart != 0 || gapAtEnd != 0)
							{
								skipLinePoints = GdiExtensionMethods.ShortenBezierCurve(skipLinePoints, gapAtStart / 2, gapAtEnd / 2);
							}

							if (null != skipLinePoints)
							{
								g.DrawBeziers(linePen, skipLinePoints);
							}
						}
					}
				}
				else // not circular without symbol gap
				{
					var trimmedLength = TrimToValidBezierLength(range.Length);
					var subLinePoints = new PointF[trimmedLength];
					Array.Copy(allLinePoints, range.LowerBound, subLinePoints, 0, trimmedLength); // Extract
					g.DrawBeziers(linePen, subLinePoints);
				}
			}
		}