Exemple #1
0
        /// <inheritdoc/>
        public override void FillOneRange(
            GraphicsPath gp,
            Processed2DPlotData pdata,
            IPlotRange range,
            IPlotArea layer,
            CSPlaneID fillDirection,
            bool ignoreMissingDataPoints,
            bool connectCircular,
            PointF[] allLinePointsShiftedAlready,
            double logicalShiftX,
            double logicalShiftY
            )
        {
            if (range.Length < 2)
            {
                return;
            }

            PointF[] linePoints = Segment2Connection_GetSubPoints(allLinePointsShiftedAlready, range, layer, connectCircular, out var lastIdx);

            if (connectCircular)
            {
                gp.AddLines(linePoints);
                gp.CloseFigure();
            }
            else
            {
                int offs = range.LowerBound;
                for (int i = 0; i < linePoints.Length - 1; i += 2)
                {
                    Logical3D r0 = layer.GetLogical3D(pdata, range.GetOriginalRowIndexFromPlotPointIndex(range.LowerBound + i));
                    r0.RX += logicalShiftX;
                    r0.RY += logicalShiftY;

                    layer.CoordinateSystem.GetIsolineFromPlaneToPoint(gp, fillDirection, r0);
                    gp.AddLine(linePoints[i].X, linePoints[i].Y, linePoints[i + 1].X, linePoints[i + 1].Y);
                    Logical3D r1 = layer.GetLogical3D(pdata, range.GetOriginalRowIndexFromPlotPointIndex(range.LowerBound + i + 1));
                    r1.RX += logicalShiftX;
                    r1.RY += logicalShiftY;

                    layer.CoordinateSystem.GetIsolineFromPointToPlane(gp, r1, fillDirection);
                    layer.CoordinateSystem.GetIsolineOnPlane(gp, fillDirection, r1, r0);
                    gp.StartFigure();
                }

                gp.CloseFigure();
            }
        }
Exemple #2
0
        /// <summary>
        /// Template to get a fill path.
        /// </summary>
        /// <param name="gp">Graphics path to fill with data.</param>
        /// <param name="pdata">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="fillDirection">Designates a bound to fill to.</param>
        /// <param name="linePoints">The points that mark the line.</param>
        /// <param name="connectCircular">If true, a circular connection is drawn.</param>
        private void FillOneRange_PreprocessedPoints(
            GraphicsPath gp,
            Processed2DPlotData pdata,
            IPlotRange range,
            IPlotArea layer,
            CSPlaneID fillDirection,
            PointF[] linePoints,
            bool connectCircular,
            double logicalShiftX,
            double logicalShiftY
            )
        {
            if (connectCircular)
            {
                gp.AddBeziers(linePoints);
                gp.CloseFigure();
            }
            else
            {
                Logical3D r0 = layer.GetLogical3D(pdata, range.OriginalFirstPoint);
                r0.RX += logicalShiftX;
                r0.RY += logicalShiftY;
                layer.CoordinateSystem.GetIsolineFromPlaneToPoint(gp, fillDirection, r0);
                gp.AddBeziers(linePoints);

                Logical3D r1 = layer.GetLogical3D(pdata, range.GetOriginalRowIndexFromPlotPointIndex(range.LowerBound + linePoints.Length - 1));
                r1.RX += logicalShiftX;
                r1.RY += logicalShiftY;

                layer.CoordinateSystem.GetIsolineFromPointToPlane(gp, r1, fillDirection);
                layer.CoordinateSystem.GetIsolineOnPlane(gp, fillDirection, r1, r0);

                gp.CloseFigure();
            }
        }
Exemple #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="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();
			}
		}
Exemple #4
0
		/// <inheritdoc/>
		public override void FillOneRange(
		GraphicsPath gp,
			Processed2DPlotData pdata,
			IPlotRange range,
			IPlotArea layer,
			CSPlaneID fillDirection,
			bool ignoreMissingDataPoints,
			bool connectCircular,
			PointF[] allLinePointsShiftedAlready,
			double logicalShiftX,
			double logicalShiftY
		)
		{
			if (range.Length < 2)
				return;

			int lastIdx;
			PointF[] linePoints = Segment2Connection_GetSubPoints(allLinePointsShiftedAlready, range, layer, connectCircular, out lastIdx);


			if (connectCircular)
			{
				gp.AddLines(linePoints);
				gp.CloseFigure();
			}
			else
			{
				int offs = range.LowerBound;
				for (int i = 0; i < linePoints.Length - 1; i += 2)
				{
					Logical3D r0 = layer.GetLogical3D(pdata, range.GetOriginalRowIndexFromPlotPointIndex(range.LowerBound + i));
					r0.RX += logicalShiftX;
					r0.RY += logicalShiftY;

					layer.CoordinateSystem.GetIsolineFromPlaneToPoint(gp, fillDirection, r0);
					gp.AddLine(linePoints[i].X, linePoints[i].Y, linePoints[i + 1].X, linePoints[i + 1].Y);
					Logical3D r1 = layer.GetLogical3D(pdata, range.GetOriginalRowIndexFromPlotPointIndex(range.LowerBound + i + 1));
					r1.RX += logicalShiftX;
					r1.RY += logicalShiftY;

					layer.CoordinateSystem.GetIsolineFromPointToPlane(gp, r1, fillDirection);
					layer.CoordinateSystem.GetIsolineOnPlane(gp, fillDirection, r1, r0);
					gp.StartFigure();
				}

				gp.CloseFigure();
			}
		}
Exemple #5
0
		public void PaintOneRange(Graphics g, IPlotArea layer, IPlotRange range, Processed2DPlotData pdata)
		{
			if (this._labelColumnProxy.Document == null)
				return;

			_cachedStringFormat.Alignment = GdiExtensionMethods.ToGdi(_alignmentX);
			_cachedStringFormat.LineAlignment = GdiExtensionMethods.ToGdi(_alignmentY);

			if (null != _attachedPlane)
				_attachedPlane = layer.UpdateCSPlaneID(_attachedPlane);

			var ptArray = pdata.PlotPointsInAbsoluteLayerCoordinates;
			Altaxo.Data.IReadableColumn labelColumn = this._labelColumnProxy.Document;

			bool isUsingVariableColorForLabelText = null != _cachedColorForIndexFunction && IsColorReceiver;
			bool isUsingVariableColorForLabelBackground = null != _cachedColorForIndexFunction &&
				(null != _backgroundStyle && _backgroundStyle.SupportsBrush && (_backgroundColorLinkage == ColorLinkage.Dependent || _backgroundColorLinkage == ColorLinkage.PreserveAlpha));
			bool isUsingVariableColor = isUsingVariableColorForLabelText || isUsingVariableColorForLabelBackground;
			BrushX clonedTextBrush = null;
			BrushX clonedBackBrush = null;
			if (isUsingVariableColorForLabelText)
				clonedTextBrush = _brush.Clone();
			if (isUsingVariableColorForLabelBackground)
				clonedBackBrush = _backgroundStyle.Brush.Clone();

			// save the graphics stat since we have to translate the origin
			var gs = g.Save();

			double xpos = 0, ypos = 0;
			double xpre, ypre;
			double xdiff, ydiff;

			bool isFormatStringContainingBraces = _labelFormatString?.IndexOf('{') >= 0;
			var culture = System.Threading.Thread.CurrentThread.CurrentCulture;

			bool mustUseLogicalCoordinates = null != this._attachedPlane || 0 != _cachedLogicalShiftX || 0 != _cachedLogicalShiftY;

			int lower = range.LowerBound;
			int upper = range.UpperBound;
			for (int j = lower; j < upper; j+=_skipFrequency)
			{
				int originalRowIndex = range.GetOriginalRowIndexFromPlotPointIndex(j);
				string label;
				if (string.IsNullOrEmpty(_labelFormatString))
				{
					label = labelColumn[originalRowIndex].ToString();
				}
				else if (!isFormatStringContainingBraces)
				{
					label = labelColumn[originalRowIndex].ToString(_labelFormatString, culture);
				}
				else
				{
					// the label format string can contain {0} for the label column item, {1} for the row index, {2} .. {4} for the x, y and z component of the data point
					label = string.Format(_labelFormatString, labelColumn[originalRowIndex], originalRowIndex, pdata.GetPhysical(0, originalRowIndex), pdata.GetPhysical(1, originalRowIndex), pdata.GetPhysical(2, originalRowIndex));
				}

				if (string.IsNullOrEmpty(label))
					continue;

				double localSymbolSize = _symbolSize;
				if (null != _cachedSymbolSizeForIndexFunction)
				{
					localSymbolSize = _cachedSymbolSizeForIndexFunction(originalRowIndex);
				}

				double localFontSize = _fontSizeOffset + _fontSizeFactor * localSymbolSize;
				if (!(localFontSize > 0))
					continue;

				_font = _font.WithSize(localFontSize);

				// Start of preparation of brushes, if a variable color is used
				if (isUsingVariableColor)
				{
					Color c = _cachedColorForIndexFunction(originalRowIndex);

					if (isUsingVariableColorForLabelText)
					{
						clonedTextBrush.Color = new NamedColor(AxoColor.FromArgb(c.A, c.R, c.G, c.B), "e");
					}
					if (isUsingVariableColorForLabelBackground)
					{
						if (_backgroundColorLinkage == ColorLinkage.PreserveAlpha)
							clonedBackBrush.Color = new NamedColor(AxoColor.FromArgb(clonedBackBrush.Color.Color.A, c.R, c.G, c.B), "e");
						else
							clonedBackBrush.Color = new NamedColor(AxoColor.FromArgb(c.A, c.R, c.G, c.B), "e");
					}
				}
				// end of preparation of brushes for variable colors

				if (mustUseLogicalCoordinates) // we must use logical coordinates because either there is a shift of logical coordinates, or an attached plane
				{
					Logical3D r3d = layer.GetLogical3D(pdata, originalRowIndex);
					r3d.RX += _cachedLogicalShiftX;
					r3d.RY += _cachedLogicalShiftY;

					if (null != this._attachedPlane)
					{
						var pp = layer.CoordinateSystem.GetPointOnPlane(this._attachedPlane, r3d);
						xpre = pp.X;
						ypre = pp.Y;
					}
					else
					{
						PointD3D pt;
						layer.CoordinateSystem.LogicalToLayerCoordinates(r3d, out xpre, out ypre);
					}
				}
				else // no shifting, thus we can use layer coordinates
				{
					xpre = ptArray[j].X;
					ypre = ptArray[j].Y;
				}

				xdiff = xpre - xpos;
				ydiff = ypre - ypos;
				xpos = xpre;
				ypos = ypre;
				g.TranslateTransform((float)xdiff, (float)ydiff);
				if (this._rotation != 0)
					g.RotateTransform((float)-this._rotation);

				this.PaintOneItem(g, label, localSymbolSize, clonedTextBrush, clonedBackBrush);

				if (this._rotation != 0)
					g.RotateTransform((float)this._rotation);

			}

			g.Restore(gs); // Restore the graphics state
		}
        protected static IEnumerable <SegmentRange> GetSegmentRanges(
            IPlotRange range,
            Func <int, double> symbolGap,
            int skipFrequency, bool connectCircular)
        {
            int lengthNonCircular    = range.Length;
            int lengthCircularMinus1 = range.Length - 1 + (connectCircular ? 1 : 0);
            // SubRange is a number of consecutive line segments, with joints where the symbol gap is zero
            double gapAtSubRangeStart = symbolGap(range.GetOriginalRowIndexFromPlotPointIndex(range.LowerBound)); // start index of the subrange
            double gapAtSubRangeEnd   = 0;
            int    indexAtSubRangeEnd;

            for (int indexAtSubRangeStart = 0; indexAtSubRangeStart < lengthCircularMinus1; indexAtSubRangeStart = indexAtSubRangeEnd, gapAtSubRangeStart = gapAtSubRangeEnd)
            {
                // search for the last index of this subrange, i.e. for a point where the gap is non-zero
                for (indexAtSubRangeEnd = indexAtSubRangeStart + 1, gapAtSubRangeEnd = 0; indexAtSubRangeEnd < lengthNonCircular; ++indexAtSubRangeEnd)
                {
                    if (0 == indexAtSubRangeEnd % skipFrequency) // calculate gap only if in skip period
                    {
                        gapAtSubRangeEnd = symbolGap(range.GetOriginalRowIndexFromPlotPointIndex(range.LowerBound + indexAtSubRangeEnd));
                    }
                    if (0 != gapAtSubRangeEnd)
                    {
                        break;
                    }
                }

                // if this is circular connected and is the last point, then use the gap of the very first point
                if (connectCircular && indexAtSubRangeEnd == lengthNonCircular)
                {
                    gapAtSubRangeEnd = symbolGap(range.GetOriginalRowIndexFromPlotPointIndex(range.LowerBound));
                }

                // test if this is a closed polygon without any gaps -> draw a closed polygon and return
                if (connectCircular && 0 == gapAtSubRangeStart && indexAtSubRangeEnd == (lengthCircularMinus1 + 1))
                {
                    // use the whole circular array to draw a closed polygon without any gaps
                    yield return(new SegmentRange()
                    {
                        IsFullRangeClosedCurve = true,
                        IndexAtSubRangeStart = indexAtSubRangeStart,
                        IndexAtSubRangeEnd = indexAtSubRangeStart,
                        GapAtSubRangeStart = 0,
                        GapAtSubRangeEnd = 0
                    });

                    break;
                }

                // adjust the end index to be valid
                if (!(indexAtSubRangeEnd <= lengthCircularMinus1))
                {
                    indexAtSubRangeEnd = lengthCircularMinus1;
                }

                yield return(new SegmentRange()
                {
                    IsFullRangeClosedCurve = false,
                    IndexAtSubRangeStart = indexAtSubRangeStart,
                    IndexAtSubRangeEnd = indexAtSubRangeEnd,
                    GapAtSubRangeStart = gapAtSubRangeStart,
                    GapAtSubRangeEnd = gapAtSubRangeEnd
                });
            }
        }
Exemple #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 < 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);
			}
		}
Exemple #8
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);
				}
			}
		}
Exemple #9
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();
            }
        }
Exemple #10
0
		protected void PaintOneRange(int axisNumber, Graphics g, IPlotArea layer, IPlotRange range, Processed2DPlotData pdata)
		{
			const double logicalClampMinimum = -10;
			const double logicalClampMaximum = 11;

			_skipFrequency = Math.Max(1, _skipFrequency);

			// Plot error bars for the dependent variable (y)
			var ptArray = pdata.PlotPointsInAbsoluteLayerCoordinates;
			var posErrCol = PositiveErrorColumn;
			var negErrCol = NegativeErrorColumn;

			if (null != posErrCol && !typeof(double).IsAssignableFrom(posErrCol.ItemType))
				posErrCol = null; // TODO make this an runtime paint error to be reported

			if (null != negErrCol && !typeof(double).IsAssignableFrom(negErrCol.ItemType))
				negErrCol = null; // TODO make this an runtime paint error to be reported

			if (posErrCol == null && negErrCol == null)
				return; // nothing to do if both error columns are null

			var strokePen = _pen.Clone();

			System.Drawing.Drawing2D.GraphicsPath errorBarPath = new System.Drawing.Drawing2D.GraphicsPath();

			Region oldClippingRegion = g.Clip;
			Region newClip = (Region)oldClippingRegion.Clone();


			int lower = range.LowerBound;
			int upper = range.UpperBound;

			for (int j = lower; j < upper; j += _skipFrequency)
			{
				int originalRowIndex = range.GetOriginalRowIndexFromPlotPointIndex(j);
				double symbolSize = null == _cachedSymbolSizeForIndexFunction ? _symbolSize : _cachedSymbolSizeForIndexFunction(originalRowIndex);
				strokePen.Width = (_lineWidth1Offset + _lineWidth1Factor * symbolSize);

				if (null != _cachedColorForIndexFunction)
					strokePen.Color = GdiColorHelper.ToNamedColor(_cachedColorForIndexFunction(originalRowIndex), "VariableColor");
				if (null != strokePen.EndCap)
					strokePen.EndCap = strokePen.EndCap.WithMinimumAbsoluteAndRelativeSize(symbolSize * _endCapSizeFactor + _endCapSizeOffset, 1 + 1E-6);

				AltaxoVariant vMeanPhysical = pdata.GetPhysical(axisNumber, originalRowIndex);
				Logical3D logicalMean = layer.GetLogical3D(pdata, originalRowIndex);
				logicalMean.RX += _cachedLogicalShiftX;
				logicalMean.RY += _cachedLogicalShiftY;

				if (!Calc.RMath.IsInIntervalCC(logicalMean.RX, logicalClampMinimum, logicalClampMaximum))
					continue;
				if (!Calc.RMath.IsInIntervalCC(logicalMean.RY, logicalClampMinimum, logicalClampMaximum))
					continue;

				var vMeanLogical = logicalMean.GetR(axisNumber);

				Logical3D logicalPos = logicalMean;
				Logical3D logicalNeg = logicalMean;
				bool logicalPosValid = false;
				bool logicalNegValid = false;

				switch (_meaningOfValues)
				{
					case ValueInterpretation.AbsoluteError:
						{
							if (posErrCol != null)
							{
								var vPosLogical = layer.Scales[axisNumber].PhysicalVariantToNormal(vMeanPhysical + Math.Abs(posErrCol[originalRowIndex]));
								vPosLogical = Calc.RMath.ClampToInterval(vPosLogical, logicalClampMinimum, logicalClampMaximum);
								logicalPos.SetR(axisNumber, vPosLogical);
								logicalPosValid = !logicalPos.IsNaN && vPosLogical != vMeanLogical;
							}

							if (negErrCol != null)
							{
								var vNegLogical = layer.Scales[axisNumber].PhysicalVariantToNormal(vMeanPhysical - Math.Abs(negErrCol[originalRowIndex]));
								vNegLogical = Calc.RMath.ClampToInterval(vNegLogical, logicalClampMinimum, logicalClampMaximum);
								logicalNeg.SetR(axisNumber, vNegLogical);
								logicalNegValid = !logicalNeg.IsNaN && vNegLogical != vMeanLogical;
							}
						}
						break;

					case ValueInterpretation.RelativeError:
						{
							if (posErrCol != null)
							{
								var vPosLogical = layer.Scales[axisNumber].PhysicalVariantToNormal(vMeanPhysical * (1 + Math.Abs(posErrCol[originalRowIndex])));
								vPosLogical = Calc.RMath.ClampToInterval(vPosLogical, logicalClampMinimum, logicalClampMaximum);
								logicalPos.SetR(axisNumber, vPosLogical);
								logicalPosValid = !logicalPos.IsNaN && vPosLogical != vMeanLogical;
							}

							if (negErrCol != null)
							{
								var vNegLogical = layer.Scales[axisNumber].PhysicalVariantToNormal(vMeanPhysical * (1 - Math.Abs(negErrCol[originalRowIndex])));
								vNegLogical = Calc.RMath.ClampToInterval(vNegLogical, logicalClampMinimum, logicalClampMaximum);
								logicalNeg.SetR(axisNumber, vNegLogical);
								logicalNegValid = !logicalNeg.IsNaN && vNegLogical != vMeanLogical;
							}
						}
						break;

					case ValueInterpretation.AbsoluteValue:
						{
							if (posErrCol != null)
							{
								var vPosLogical = layer.Scales[axisNumber].PhysicalVariantToNormal(posErrCol[originalRowIndex]);
								vPosLogical = Calc.RMath.ClampToInterval(vPosLogical, logicalClampMinimum, logicalClampMaximum);
								logicalPos.SetR(axisNumber, vPosLogical);
								logicalPosValid = !logicalPos.IsNaN && vPosLogical != vMeanLogical;
							}

							if (negErrCol != null)
							{
								var vNegLogical = layer.Scales[axisNumber].PhysicalVariantToNormal(negErrCol[originalRowIndex]);
								vNegLogical = Calc.RMath.ClampToInterval(vNegLogical, logicalClampMinimum, logicalClampMaximum);
								logicalNeg.SetR(axisNumber, vNegLogical);
								logicalNegValid = !logicalNeg.IsNaN && vNegLogical != vMeanLogical;
							}

							if (object.ReferenceEquals(negErrCol, posErrCol))
							{
								logicalNegValid = false; // then we need only to plot the positive column, since both colums are identical
							}
						}
						break;
				} // end switch

				if (!(logicalPosValid || logicalNegValid))
					continue; // nothing to do for this point if both pos and neg logical point are invalid.

				if (logicalNegValid)
				{
					errorBarPath.Reset();
					layer.CoordinateSystem.GetIsoline(errorBarPath, logicalMean, logicalNeg);
					PointF[] shortenedPathPoints = null;
					bool shortenedPathPointsCalculated = false;
					if (_useSymbolGap)
					{
						double gap = _symbolGapOffset + _symbolGapFactor * symbolSize;
						if (gap > 0)
						{
							errorBarPath.Flatten();
							var pathPoints = errorBarPath.PathPoints;
							shortenedPathPoints = GdiExtensionMethods.ShortenedBy(pathPoints, RADouble.NewAbs(gap / 2), RADouble.NewAbs(0));
							shortenedPathPointsCalculated = true;
							if (null == shortenedPathPoints && _forceVisibilityOfEndCap && !(strokePen.EndCap is Altaxo.Graph.Gdi.LineCaps.FlatCap))
							{
								var totalLineLength = GdiExtensionMethods.TotalLineLength(pathPoints);
								var shortTheLineBy = Math.Max(0, totalLineLength - 0.125 * strokePen.Width);
								shortenedPathPoints = GdiExtensionMethods.ShortenedBy(pathPoints, RADouble.NewAbs(shortTheLineBy), RADouble.NewAbs(0));
							}
						}
					}

					if (shortenedPathPointsCalculated)
					{
						if (null != shortenedPathPoints)
						{
							g.DrawLines(strokePen, shortenedPathPoints);
						}
					}
					else
					{
						g.DrawPath(strokePen, errorBarPath);
					}
				}

				if (logicalPosValid)
				{
					errorBarPath.Reset();
					layer.CoordinateSystem.GetIsoline(errorBarPath, logicalMean, logicalPos);
					PointF[] shortenedPathPoints = null;
					bool shortenedPathPointsCalculated = false;


					if (_useSymbolGap)
					{
						double gap = _symbolGapOffset + _symbolGapFactor * symbolSize;
						if (gap > 0)
						{
							errorBarPath.Flatten();
							var pathPoints = errorBarPath.PathPoints;
							shortenedPathPoints = GdiExtensionMethods.ShortenedBy(pathPoints, RADouble.NewAbs(gap / 2), RADouble.NewAbs(0));
							shortenedPathPointsCalculated = true;
							if (null == shortenedPathPoints && _forceVisibilityOfEndCap && !(strokePen.EndCap is Altaxo.Graph.Gdi.LineCaps.FlatCap))
							{
								var totalLineLength = GdiExtensionMethods.TotalLineLength(pathPoints);
								var shortTheLineBy = Math.Max(0, totalLineLength - 0.125 * strokePen.Width);
								shortenedPathPoints = GdiExtensionMethods.ShortenedBy(pathPoints, RADouble.NewAbs(shortTheLineBy), RADouble.NewAbs(0));
							}

						}
					}

					if (shortenedPathPointsCalculated)
					{
						if (null != shortenedPathPoints)
						{
							g.DrawLines(strokePen, shortenedPathPoints);
						}
					}
					else
					{
						g.DrawPath(strokePen, errorBarPath);
					}
				}
			}

			g.Clip = oldClippingRegion;

		}
Exemple #11
0
        private void PaintOneRange(Graphics g, IPlotArea layer, IPlotRange range, Processed2DPlotData pdata)
        {
            // adjust the skip frequency if it was not set appropriate
            if (_skipFrequency <= 0)
            {
                _skipFrequency = 1;
            }

            var dropTargets = new List <CSPlaneID>(_dropTargets.Select(id => layer.UpdateCSPlaneID(id)));

            if (_additionalDropTargetIsEnabled)
            {
                CSPlaneID userPlane;
                if (_additionalDropTargetUsePhysicalBaseValue)
                {
                    userPlane = new CSPlaneID(_additionalDropTargetPerpendicularAxis, layer.Scales[_additionalDropTargetPerpendicularAxis].PhysicalVariantToNormal(_additionalDropTargetBaseValue));
                }
                else
                {
                    userPlane = new CSPlaneID(_additionalDropTargetPerpendicularAxis, _additionalDropTargetBaseValue);
                }
                dropTargets.Add(userPlane);
            }

            // paint the scatter style

            PointD3D pos   = PointD3D.Empty;
            var      gpath = new GraphicsPath();

            if (null == _cachedSymbolSizeForIndexFunction && null == _cachedColorForIndexFunction) // using a constant symbol size and constant color
            {
                // update pen widths
                var    pen = _pen.Clone();
                double w1  = _lineWidth1Offset + _lineWidth1Factor * _cachedSymbolSize;
                pen.Width = w1;

                var gapStart = 0.5 * (_gapAtStartOffset + _gapAtStartFactor * _cachedSymbolSize);
                var gapEnd   = 0.5 * (_gapAtEndOffset + _gapAtEndFactor * _cachedSymbolSize);

                int lower = range.LowerBound;
                int upper = range.UpperBound;

                for (int j = lower; j < upper; j += _skipFrequency)
                {
                    var originalRowIndex = range.GetOriginalRowIndexFromPlotPointIndex(j);

                    Logical3D r3d = layer.GetLogical3D(pdata, originalRowIndex);
                    r3d.RX += _cachedLogicalShiftX;
                    r3d.RY += _cachedLogicalShiftY;

                    foreach (CSPlaneID id in dropTargets)
                    {
                        gpath.Reset();
                        layer.CoordinateSystem.GetIsolineFromPointToPlane(gpath, r3d, id);
                        PointF[] shortenedPathPoints = null;
                        if (gapStart != 0 || gapEnd != 0)
                        {
                            gpath.Flatten();
                            var pathPoints = gpath.PathPoints;
                            shortenedPathPoints = GdiExtensionMethods.ShortenedBy(pathPoints, RADouble.NewAbs(gapStart), RADouble.NewAbs(gapEnd));
                            if (null != shortenedPathPoints)
                            {
                                g.DrawLines(pen, shortenedPathPoints);
                            }
                        }
                        else
                        {
                            g.DrawPath(pen, gpath);
                        }
                    }
                }
            }
            else // using a variable symbol size or variable symbol color
            {
                int lower = range.LowerBound;
                int upper = range.UpperBound;
                for (int j = lower; j < upper; j += _skipFrequency)
                {
                    var originalRowIndex = range.GetOriginalRowIndexFromPlotPointIndex(j);
                    var pen = _pen.Clone();
                    if (null == _cachedColorForIndexFunction)
                    {
                        _cachedSymbolSize = _cachedSymbolSizeForIndexFunction(originalRowIndex);
                        double w1 = _lineWidth1Offset + _lineWidth1Factor * _cachedSymbolSize;
                        pen.Width = w1;
                    }
                    else
                    {
                        _cachedSymbolSize = null == _cachedSymbolSizeForIndexFunction ? _cachedSymbolSize : _cachedSymbolSizeForIndexFunction(originalRowIndex);
                        double w1 = _lineWidth1Offset + _lineWidth1Factor * _cachedSymbolSize;

                        var customSymbolColor = _cachedColorForIndexFunction(originalRowIndex);
                        pen.Width = w1;
                        pen.Color = NamedColor.FromArgb(customSymbolColor.A, customSymbolColor.R, customSymbolColor.G, customSymbolColor.B);
                    }

                    var gapStart = 0.5 * (_gapAtStartOffset + _gapAtStartFactor * _cachedSymbolSize);
                    var gapEnd   = 0.5 * (_gapAtEndOffset + _gapAtEndFactor * _cachedSymbolSize);

                    Logical3D r3d = layer.GetLogical3D(pdata, originalRowIndex);
                    r3d.RX += _cachedLogicalShiftX;
                    r3d.RY += _cachedLogicalShiftY;

                    foreach (CSPlaneID id in _dropTargets)
                    {
                        gpath.Reset();
                        layer.CoordinateSystem.GetIsolineFromPointToPlane(gpath, r3d, id);
                        PointF[] shortenedPathPoints = null;
                        if (gapStart != 0 || gapEnd != 0)
                        {
                            gpath.Flatten();
                            var pathPoints = gpath.PathPoints;
                            shortenedPathPoints = GdiExtensionMethods.ShortenedBy(pathPoints, RADouble.NewAbs(gapStart), RADouble.NewAbs(gapEnd));
                            if (null != shortenedPathPoints)
                            {
                                g.DrawLines(pen, shortenedPathPoints);
                            }
                        }
                        else
                        {
                            g.DrawPath(pen, gpath);
                        }
                    }
                }
            }
        }
		protected void PaintOneRange(Graphics g, IPlotArea layer, IPlotRange range, Processed2DPlotData pdata)
		{
			const double logicalClampMinimum = -10;
			const double logicalClampMaximum = 11;

			// Plot error bars for the dependent variable (y)
			var columnX = ColumnX;
			var columnY = ColumnY;

			if (columnX == null || columnY == null)
				return; // nothing to do if both error columns are null

			if (!typeof(double).IsAssignableFrom(columnX.ItemType) || !typeof(double).IsAssignableFrom(columnY.ItemType))
				return; // TODO make this an runtime paint error to be reported

			var strokePen = _strokePen.Clone();

			using (GraphicsPath isoLine = new GraphicsPath())
			{

				int lower = range.LowerBound;
				int upper = range.UpperBound;


				for (int j = lower; j < upper; j += _skipFrequency)
				{
					int originalRowIndex = range.GetOriginalRowIndexFromPlotPointIndex(j);
					double symbolSize = null == _cachedSymbolSizeForIndexFunction ? _symbolSize : _cachedSymbolSizeForIndexFunction(originalRowIndex);

					strokePen.Width = (_lineWidth1Offset + _lineWidth1Factor * symbolSize);

					if (null != _cachedColorForIndexFunction)
						strokePen.Color = GdiColorHelper.ToNamedColor(_cachedColorForIndexFunction(originalRowIndex), "VariableColor");

					if (!(strokePen.EndCap is LineCaps.FlatCap))
						strokePen.EndCap = strokePen.EndCap.WithMinimumAbsoluteAndRelativeSize(symbolSize * _endCapSizeFactor + _endCapSizeOffset, 1 + 1E-6);

					// Calculate target
					AltaxoVariant targetX, targetY;
					switch (_meaningOfValues)
					{
						case ValueInterpretation.AbsoluteDifference:
							{
								targetX = pdata.GetXPhysical(originalRowIndex) + columnX[originalRowIndex];
								targetY = pdata.GetYPhysical(originalRowIndex) + columnY[originalRowIndex];
							}
							break;

						case ValueInterpretation.AbsoluteValue:
							{
								targetX = columnX[originalRowIndex];
								targetY = columnY[originalRowIndex];
							}
							break;

						default:
							throw new NotImplementedException(nameof(_meaningOfValues));
					}

					var logicalTarget = layer.GetLogical3D(targetX, targetY);
					var logicalOrigin = layer.GetLogical3D(pdata, originalRowIndex);

					if (!_independentOnShiftingGroupStyles && (0 != _cachedLogicalShiftX || 0 != _cachedLogicalShiftY))
					{
						logicalOrigin.RX += _cachedLogicalShiftX;
						logicalOrigin.RY += _cachedLogicalShiftY;
						logicalTarget.RX += _cachedLogicalShiftX;
						logicalTarget.RY += _cachedLogicalShiftY;
					}

					if (!Calc.RMath.IsInIntervalCC(logicalOrigin.RX, logicalClampMinimum, logicalClampMaximum))
						continue;
					if (!Calc.RMath.IsInIntervalCC(logicalOrigin.RY, logicalClampMinimum, logicalClampMaximum))
						continue;
					if (!Calc.RMath.IsInIntervalCC(logicalOrigin.RZ, logicalClampMinimum, logicalClampMaximum))
						continue;

					if (!Calc.RMath.IsInIntervalCC(logicalTarget.RX, logicalClampMinimum, logicalClampMaximum))
						continue;
					if (!Calc.RMath.IsInIntervalCC(logicalTarget.RY, logicalClampMinimum, logicalClampMaximum))
						continue;
					if (!Calc.RMath.IsInIntervalCC(logicalTarget.RZ, logicalClampMinimum, logicalClampMaximum))
						continue;

					isoLine.Reset();

					layer.CoordinateSystem.GetIsoline(isoLine, logicalOrigin, logicalTarget);
					if (null == isoLine)
						continue;

					PointF[] isoLinePathPoints = null;

					if (_useManualVectorLength)
					{
						isoLine.Flatten();
						isoLinePathPoints = isoLine.PathPoints;

						double length = _vectorLengthOffset + _vectorLengthFactor * symbolSize;
						double isoLineLength = isoLinePathPoints.TotalLineLength();
						isoLinePathPoints = isoLinePathPoints.ShortenedBy(RADouble.NewAbs(0), RADouble.NewAbs(isoLineLength - length));
						if (null == isoLine)
							continue;
					}

					if (_useSymbolGap)
					{
						if (null == isoLinePathPoints)
						{
							isoLine.Flatten();
							isoLinePathPoints = isoLine.PathPoints;
						}

						double gap = _symbolGapOffset + _symbolGapFactor * symbolSize;
						if (gap != 0)
						{
							isoLinePathPoints = isoLinePathPoints.ShortenedBy(RADouble.NewAbs(gap / 2), RADouble.NewAbs(0));
							if (null == isoLine)
								continue;
						}
					}

					if (null != isoLinePathPoints)
						g.DrawLines(_strokePen, isoLinePathPoints);
					else
						g.DrawPath(strokePen, isoLine);
				}

			}
		}
Exemple #13
0
		private void PaintOneRange(Graphics g, IPlotArea layer, IPlotRange range, Processed2DPlotData pdata)
		{
			// adjust the skip frequency if it was not set appropriate
			if (_skipFrequency <= 0)
				_skipFrequency = 1;

			var dropTargets = new List<CSPlaneID>(_dropTargets.Select(id => layer.UpdateCSPlaneID(id)));
			if (_additionalDropTargetIsEnabled)
			{
				CSPlaneID userPlane;
				if (_additionalDropTargetUsePhysicalBaseValue)
				{
					userPlane = new CSPlaneID(_additionalDropTargetPerpendicularAxis, layer.Scales[_additionalDropTargetPerpendicularAxis].PhysicalVariantToNormal(_additionalDropTargetBaseValue));
				}
				else
				{
					userPlane = new CSPlaneID(_additionalDropTargetPerpendicularAxis, _additionalDropTargetBaseValue);
				}
				dropTargets.Add(userPlane);
			}

			// paint the scatter style

			PointD3D pos = PointD3D.Empty;
			var gpath = new GraphicsPath();

			if (null == _cachedSymbolSizeForIndexFunction && null == _cachedColorForIndexFunction) // using a constant symbol size and constant color
			{
				// update pen widths
				var pen = _pen.Clone();
				double w1 = _lineWidth1Offset + _lineWidth1Factor * _cachedSymbolSize;
				pen.Width = w1;

				var gapStart = 0.5 * (_gapAtStartOffset + _gapAtStartFactor * _cachedSymbolSize);
				var gapEnd = 0.5 * (_gapAtEndOffset + _gapAtEndFactor * _cachedSymbolSize);


				int lower = range.LowerBound;
				int upper = range.UpperBound;

				for (int j = lower; j < upper; j += _skipFrequency)
				{
					var originalRowIndex = range.GetOriginalRowIndexFromPlotPointIndex(j);

					Logical3D r3d = layer.GetLogical3D(pdata, originalRowIndex);
					r3d.RX += _cachedLogicalShiftX;
					r3d.RY += _cachedLogicalShiftY;

					foreach (CSPlaneID id in dropTargets)
					{
						gpath.Reset();
						layer.CoordinateSystem.GetIsolineFromPointToPlane(gpath, r3d, id);
						PointF[] shortenedPathPoints = null;
						if (gapStart != 0 || gapEnd != 0)
						{
							gpath.Flatten();
							var pathPoints = gpath.PathPoints;
							shortenedPathPoints = GdiExtensionMethods.ShortenedBy(pathPoints, RADouble.NewAbs(gapStart), RADouble.NewAbs(gapEnd));
							if (null != shortenedPathPoints)
								g.DrawLines(pen, shortenedPathPoints);
						}
						else
						{
							g.DrawPath(pen, gpath);
						}
					}
				}

			}
			else // using a variable symbol size or variable symbol color
			{

				int lower = range.LowerBound;
				int upper = range.UpperBound;
				for (int j = lower; j < upper; j += _skipFrequency)
				{
					var originalRowIndex = range.GetOriginalRowIndexFromPlotPointIndex(j);
					var pen = _pen.Clone();
					if (null == _cachedColorForIndexFunction)
					{
						_cachedSymbolSize = _cachedSymbolSizeForIndexFunction(originalRowIndex);
						double w1 = _lineWidth1Offset + _lineWidth1Factor * _cachedSymbolSize;
						pen.Width = w1;
					}
					else
					{
						_cachedSymbolSize = null == _cachedSymbolSizeForIndexFunction ? _cachedSymbolSize : _cachedSymbolSizeForIndexFunction(originalRowIndex);
						double w1 = _lineWidth1Offset + _lineWidth1Factor * _cachedSymbolSize;

						var customSymbolColor = _cachedColorForIndexFunction(originalRowIndex);
						pen.Width = w1;
						pen.Color = NamedColor.FromArgb(customSymbolColor.A, customSymbolColor.R, customSymbolColor.G, customSymbolColor.B);
					}

					var gapStart = 0.5 * (_gapAtStartOffset + _gapAtStartFactor * _cachedSymbolSize);
					var gapEnd = 0.5 * (_gapAtEndOffset + _gapAtEndFactor * _cachedSymbolSize);

					Logical3D r3d = layer.GetLogical3D(pdata, originalRowIndex);
					r3d.RX += _cachedLogicalShiftX;
					r3d.RY += _cachedLogicalShiftY;

					foreach (CSPlaneID id in _dropTargets)
					{
						gpath.Reset();
						layer.CoordinateSystem.GetIsolineFromPointToPlane(gpath, r3d, id);
						PointF[] shortenedPathPoints = null;
						if (gapStart != 0 || gapEnd != 0)
						{
							gpath.Flatten();
							var pathPoints = gpath.PathPoints;
							shortenedPathPoints = GdiExtensionMethods.ShortenedBy(pathPoints, RADouble.NewAbs(gapStart), RADouble.NewAbs(gapEnd));
							if (null != shortenedPathPoints)
								g.DrawLines(pen, shortenedPathPoints);
						}
						else
						{
							g.DrawPath(pen, gpath);
						}
					}
				}

			}
		}
Exemple #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);
				}
			}
		}
Exemple #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)
		{
			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);
				}
			}
		}
Exemple #16
0
		private void PaintOneRange(
			Graphics g,
			IPlotArea layer,
			PointF[] plotPositions,
			IPlotRange range,
			IScatterSymbol scatterSymbol,
			ref CachedPathData cachedPathData,
			ref CachedBrushData cachedBrushData)
		{
			var ptArray = plotPositions;

			float xpos = 0, ypos = 0;
			float xdiff, ydiff;

			int originalIndex;

			// save the graphics stat since we have to translate the origin
			System.Drawing.Drawing2D.GraphicsState gs = g.Save();

			if (null == _cachedSymbolSizeForIndexFunction && null == _cachedColorForIndexFunction) // using a constant symbol size
			{
				// calculate the path only once
				CalculatePaths(scatterSymbol, _symbolSize, ref cachedPathData);
				CalculateBrushes(scatterSymbol, _color, cachedPathData, ref cachedBrushData);



				for (int plotPointIndex = range.LowerBound; plotPointIndex < range.UpperBound; plotPointIndex += _skipFreq)
				{
					xdiff = ptArray[plotPointIndex].X - xpos;
					ydiff = ptArray[plotPointIndex].Y - ypos;
					xpos = ptArray[plotPointIndex].X;
					ypos = ptArray[plotPointIndex].Y;
					g.TranslateTransform(xdiff, ydiff);

					if (null != cachedPathData.InsetPath)
						g.FillPath(cachedBrushData.InsetBrush, cachedPathData.InsetPath);

					if (null != cachedPathData.FillPath)
						g.FillPath(cachedBrushData.FillBrush, cachedPathData.FillPath);

					if (null != cachedPathData.FramePath)
						g.FillPath(cachedBrushData.FrameBrush, cachedPathData.FramePath);
				} // end for


			}
			else // using a variable symbol size or variable symbol color
			{
				CalculatePaths(scatterSymbol, _symbolSize, ref cachedPathData);
				CalculateBrushes(scatterSymbol, _color, cachedPathData, ref cachedBrushData);

				for (int plotPointIndex = range.LowerBound; plotPointIndex < range.UpperBound; plotPointIndex += _skipFreq)
				{
					originalIndex = range.GetOriginalRowIndexFromPlotPointIndex(plotPointIndex);

					if (null == _cachedColorForIndexFunction)
					{
						double customSymbolSize = _cachedSymbolSizeForIndexFunction(originalIndex);
						CalculatePaths(scatterSymbol, customSymbolSize, ref cachedPathData);
					}
					else
					{
						double customSymbolSize = null == _cachedSymbolSizeForIndexFunction ? _symbolSize : _cachedSymbolSizeForIndexFunction(originalIndex);
						var customSymbolColor = _cachedColorForIndexFunction(originalIndex);
						CalculatePaths(scatterSymbol, customSymbolSize, ref cachedPathData);
						CalculateBrushes(scatterSymbol, NamedColor.FromArgb(customSymbolColor.A, customSymbolColor.R, customSymbolColor.G, customSymbolColor.B), cachedPathData, ref cachedBrushData);
					}

					xdiff = ptArray[plotPointIndex].X - xpos;
					ydiff = ptArray[plotPointIndex].Y - ypos;
					xpos = ptArray[plotPointIndex].X;
					ypos = ptArray[plotPointIndex].Y;
					g.TranslateTransform(xdiff, ydiff);

					if (null != cachedPathData.InsetPath)
						g.FillPath(cachedBrushData.InsetBrush, cachedPathData.InsetPath);

					if (null != cachedPathData.FillPath)
						g.FillPath(cachedBrushData.FillBrush, cachedPathData.FillPath);

					if (null != cachedPathData.FramePath)
						g.FillPath(cachedBrushData.FrameBrush, cachedPathData.FramePath);

				}
			}

			g.Restore(gs); // Restore the graphics state
		}
Exemple #17
0
        private void PaintOneRange(
            Graphics g,
            IPlotArea layer,
            PointF[] plotPositions,
            IPlotRange range,
            IScatterSymbol scatterSymbol,
            ref CachedPathData cachedPathData,
            ref CachedBrushData cachedBrushData)
        {
            var ptArray = plotPositions;

            float xpos = 0, ypos = 0;
            float xdiff, ydiff;

            int originalIndex;

            // save the graphics stat since we have to translate the origin
            System.Drawing.Drawing2D.GraphicsState gs = g.Save();

            if (null == _cachedSymbolSizeForIndexFunction && null == _cachedColorForIndexFunction) // using a constant symbol size
            {
                // calculate the path only once
                CalculatePaths(scatterSymbol, _symbolSize, ref cachedPathData);
                CalculateBrushes(scatterSymbol, _color, cachedPathData, ref cachedBrushData);

                for (int plotPointIndex = range.LowerBound; plotPointIndex < range.UpperBound; plotPointIndex += _skipFreq)
                {
                    xdiff = ptArray[plotPointIndex].X - xpos;
                    ydiff = ptArray[plotPointIndex].Y - ypos;
                    xpos  = ptArray[plotPointIndex].X;
                    ypos  = ptArray[plotPointIndex].Y;
                    g.TranslateTransform(xdiff, ydiff);

                    if (null != cachedPathData.InsetPath)
                    {
                        g.FillPath(cachedBrushData.InsetBrush, cachedPathData.InsetPath);
                    }

                    if (null != cachedPathData.FillPath)
                    {
                        g.FillPath(cachedBrushData.FillBrush, cachedPathData.FillPath);
                    }

                    if (null != cachedPathData.FramePath)
                    {
                        g.FillPath(cachedBrushData.FrameBrush, cachedPathData.FramePath);
                    }
                } // end for
            }
            else  // using a variable symbol size or variable symbol color
            {
                CalculatePaths(scatterSymbol, _symbolSize, ref cachedPathData);
                CalculateBrushes(scatterSymbol, _color, cachedPathData, ref cachedBrushData);

                for (int plotPointIndex = range.LowerBound; plotPointIndex < range.UpperBound; plotPointIndex += _skipFreq)
                {
                    originalIndex = range.GetOriginalRowIndexFromPlotPointIndex(plotPointIndex);

                    if (null == _cachedColorForIndexFunction)
                    {
                        double customSymbolSize = _cachedSymbolSizeForIndexFunction(originalIndex);
                        CalculatePaths(scatterSymbol, customSymbolSize, ref cachedPathData);
                    }
                    else
                    {
                        double customSymbolSize  = null == _cachedSymbolSizeForIndexFunction ? _symbolSize : _cachedSymbolSizeForIndexFunction(originalIndex);
                        var    customSymbolColor = _cachedColorForIndexFunction(originalIndex);
                        CalculatePaths(scatterSymbol, customSymbolSize, ref cachedPathData);
                        CalculateBrushes(scatterSymbol, NamedColor.FromArgb(customSymbolColor.A, customSymbolColor.R, customSymbolColor.G, customSymbolColor.B), cachedPathData, ref cachedBrushData);
                    }

                    xdiff = ptArray[plotPointIndex].X - xpos;
                    ydiff = ptArray[plotPointIndex].Y - ypos;
                    xpos  = ptArray[plotPointIndex].X;
                    ypos  = ptArray[plotPointIndex].Y;
                    g.TranslateTransform(xdiff, ydiff);

                    if (null != cachedPathData.InsetPath)
                    {
                        g.FillPath(cachedBrushData.InsetBrush, cachedPathData.InsetPath);
                    }

                    if (null != cachedPathData.FillPath)
                    {
                        g.FillPath(cachedBrushData.FillBrush, cachedPathData.FillPath);
                    }

                    if (null != cachedPathData.FramePath)
                    {
                        g.FillPath(cachedBrushData.FrameBrush, cachedPathData.FramePath);
                    }
                }
            }

            g.Restore(gs); // Restore the graphics state
        }
        protected void PaintOneRange(Graphics g, IPlotArea layer, IPlotRange range, Processed2DPlotData pdata)
        {
            const double logicalClampMinimum = -10;
            const double logicalClampMaximum = 11;

            // Plot error bars for the dependent variable (y)
            var columnX = ColumnX;
            var columnY = ColumnY;

            if (columnX == null || columnY == null)
            {
                return; // nothing to do if both error columns are null
            }
            if (!typeof(double).IsAssignableFrom(columnX.ItemType) || !typeof(double).IsAssignableFrom(columnY.ItemType))
            {
                return; // TODO make this an runtime paint error to be reported
            }
            var strokePen = _strokePen.Clone();

            using (var isoLine = new GraphicsPath())
            {
                int lower = range.LowerBound;
                int upper = range.UpperBound;

                for (int j = lower; j < upper; j += _skipFrequency)
                {
                    int    originalRowIndex = range.GetOriginalRowIndexFromPlotPointIndex(j);
                    double symbolSize       = null == _cachedSymbolSizeForIndexFunction ? _symbolSize : _cachedSymbolSizeForIndexFunction(originalRowIndex);

                    strokePen.Width = (_lineWidth1Offset + _lineWidth1Factor * symbolSize);

                    if (null != _cachedColorForIndexFunction)
                    {
                        strokePen.Color = GdiColorHelper.ToNamedColor(_cachedColorForIndexFunction(originalRowIndex), "VariableColor");
                    }

                    if (!(strokePen.EndCap is LineCaps.FlatCap))
                    {
                        strokePen.EndCap = strokePen.EndCap.WithMinimumAbsoluteAndRelativeSize(symbolSize * _endCapSizeFactor + _endCapSizeOffset, 1 + 1E-6);
                    }

                    // Calculate target
                    AltaxoVariant targetX, targetY;
                    switch (_meaningOfValues)
                    {
                    case ValueInterpretation.AbsoluteDifference:
                    {
                        targetX = pdata.GetXPhysical(originalRowIndex) + columnX[originalRowIndex];
                        targetY = pdata.GetYPhysical(originalRowIndex) + columnY[originalRowIndex];
                    }
                    break;

                    case ValueInterpretation.AbsoluteValue:
                    {
                        targetX = columnX[originalRowIndex];
                        targetY = columnY[originalRowIndex];
                    }
                    break;

                    default:
                        throw new NotImplementedException(nameof(_meaningOfValues));
                    }

                    var logicalTarget = layer.GetLogical3D(targetX, targetY);
                    var logicalOrigin = layer.GetLogical3D(pdata, originalRowIndex);

                    if (!_independentOnShiftingGroupStyles && (0 != _cachedLogicalShiftX || 0 != _cachedLogicalShiftY))
                    {
                        logicalOrigin.RX += _cachedLogicalShiftX;
                        logicalOrigin.RY += _cachedLogicalShiftY;
                        logicalTarget.RX += _cachedLogicalShiftX;
                        logicalTarget.RY += _cachedLogicalShiftY;
                    }

                    if (!Calc.RMath.IsInIntervalCC(logicalOrigin.RX, logicalClampMinimum, logicalClampMaximum))
                    {
                        continue;
                    }
                    if (!Calc.RMath.IsInIntervalCC(logicalOrigin.RY, logicalClampMinimum, logicalClampMaximum))
                    {
                        continue;
                    }
                    if (!Calc.RMath.IsInIntervalCC(logicalOrigin.RZ, logicalClampMinimum, logicalClampMaximum))
                    {
                        continue;
                    }

                    if (!Calc.RMath.IsInIntervalCC(logicalTarget.RX, logicalClampMinimum, logicalClampMaximum))
                    {
                        continue;
                    }
                    if (!Calc.RMath.IsInIntervalCC(logicalTarget.RY, logicalClampMinimum, logicalClampMaximum))
                    {
                        continue;
                    }
                    if (!Calc.RMath.IsInIntervalCC(logicalTarget.RZ, logicalClampMinimum, logicalClampMaximum))
                    {
                        continue;
                    }

                    isoLine.Reset();

                    layer.CoordinateSystem.GetIsoline(isoLine, logicalOrigin, logicalTarget);
                    if (null == isoLine)
                    {
                        continue;
                    }

                    PointF[] isoLinePathPoints = null;

                    if (_useManualVectorLength)
                    {
                        isoLine.Flatten();
                        isoLinePathPoints = isoLine.PathPoints;

                        double length        = _vectorLengthOffset + _vectorLengthFactor * symbolSize;
                        double isoLineLength = isoLinePathPoints.TotalLineLength();
                        isoLinePathPoints = isoLinePathPoints.ShortenedBy(RADouble.NewAbs(0), RADouble.NewAbs(isoLineLength - length));
                        if (null == isoLine)
                        {
                            continue;
                        }
                    }

                    if (_useSymbolGap)
                    {
                        if (null == isoLinePathPoints)
                        {
                            isoLine.Flatten();
                            isoLinePathPoints = isoLine.PathPoints;
                        }

                        double gap = _symbolGapOffset + _symbolGapFactor * symbolSize;
                        if (gap != 0)
                        {
                            isoLinePathPoints = isoLinePathPoints.ShortenedBy(RADouble.NewAbs(gap / 2), RADouble.NewAbs(0));
                            if (null == isoLine)
                            {
                                continue;
                            }
                        }
                    }

                    if (null != isoLinePathPoints)
                    {
                        g.DrawLines(_strokePen, isoLinePathPoints);
                    }
                    else
                    {
                        g.DrawPath(strokePen, isoLine);
                    }
                }
            }
        }
Exemple #19
0
		/// <summary>
		/// Template to get a fill path.
		/// </summary>
		/// <param name="gp">Graphics path to fill with data.</param>
		/// <param name="pdata">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="fillDirection">Designates a bound to fill to.</param>
		/// <param name="linePoints">The points that mark the line.</param>
		/// <param name="connectCircular">If true, a circular connection is drawn.</param>
		private void FillOneRange_PreprocessedPoints(
		GraphicsPath gp,
			Processed2DPlotData pdata,
			IPlotRange range,
			IPlotArea layer,
			CSPlaneID fillDirection,
			PointF[] linePoints,
			bool connectCircular,
			double logicalShiftX,
			double logicalShiftY
		)
		{
			if (connectCircular)
			{
				gp.AddBeziers(linePoints);
				gp.CloseFigure();

			}
			else
			{
				Logical3D r0 = layer.GetLogical3D(pdata, range.OriginalFirstPoint);
				r0.RX += logicalShiftX;
				r0.RY += logicalShiftY;
				layer.CoordinateSystem.GetIsolineFromPlaneToPoint(gp, fillDirection, r0);
				gp.AddBeziers(linePoints);

				Logical3D r1 = layer.GetLogical3D(pdata, range.GetOriginalRowIndexFromPlotPointIndex(range.LowerBound + linePoints.Length - 1));
				r1.RX += logicalShiftX;
				r1.RY += logicalShiftY;

				layer.CoordinateSystem.GetIsolineFromPointToPlane(gp, r1, fillDirection);
				layer.CoordinateSystem.GetIsolineOnPlane(gp, fillDirection, r1, r0);

				gp.CloseFigure();
			}

		}