Пример #1
0
        /// <summary>
        /// Determines whether the plot items in <paramref name="coll"/> can be plotted as stack. Presumption is that all plot items
        /// have the same number of plot points, and that all items have the same order of x values associated with the plot points.
        /// </summary>
        /// <param name="layer">Plot layer.</param>
        /// <param name="coll">Collection of plot items.</param>
        /// <param name="plotDataList">Output: dictionary with associates each plot item with a list of processed plot data.</param>
        /// <returns>Returns <c>true</c> if the plot items in <paramref name="coll"/> can be plotted as stack; otherwise, <c>false</c>.</returns>
        public static bool CanUseStyle(IPlotArea layer, PlotItemCollection coll, out Dictionary <G3DPlotItem, Processed3DPlotData> plotDataList)
        {
            plotDataList = new Dictionary <G3DPlotItem, Processed3DPlotData>();

            AltaxoVariant[] xArray = null;
            AltaxoVariant[] yArray = null;

            int idx = -1;

            foreach (IGPlotItem pi in coll)
            {
                if (pi is G3DPlotItem)
                {
                    idx++;
                    var gpi = (G3DPlotItem)pi;
                    Processed3DPlotData pdata = gpi.GetRangesAndPoints(layer);
                    plotDataList.Add(gpi, pdata);

                    if (xArray == null)
                    {
                        xArray = new AltaxoVariant[pdata.RangeList.PlotPointCount];
                        yArray = new AltaxoVariant[pdata.RangeList.PlotPointCount];

                        int j = -1;
                        foreach (int originalIndex in pdata.RangeList.OriginalRowIndices())
                        {
                            j++;
                            xArray[j] = pdata.GetXPhysical(originalIndex);
                            yArray[j] = pdata.GetYPhysical(originalIndex);
                        }
                    }
                    else // this is not the first item
                    {
                        if (pdata.RangeList.PlotPointCount != xArray.Length)
                        {
                            return(false);
                        }

                        int j = -1;
                        foreach (int originalIndex in pdata.RangeList.OriginalRowIndices())
                        {
                            j++;

                            if (xArray[j] != pdata.GetXPhysical(originalIndex))
                            {
                                return(false);
                            }

                            if (yArray[j] != pdata.GetYPhysical(originalIndex))
                            {
                                return(false);
                            }
                        }
                    }
                }
            }

            return(idx >= 1);
        }
Пример #2
0
        public void PrepareGroupStyles(PlotGroupStyleCollection externalGroups, PlotGroupStyleCollection localGroups, IPlotArea layer, Processed3DPlotData pdata)
        {
            // first, we have to calculate the span of logical values from the minimum logical value to the maximum logical value
            int numberOfItems = 0;

            if (null != pdata)
            {
                double minLogicalX = double.MaxValue;
                double maxLogicalX = double.MinValue;
                double minLogicalY = double.MaxValue;
                double maxLogicalY = double.MinValue;
                foreach (int originalRowIndex in pdata.RangeList.OriginalRowIndices())
                {
                    numberOfItems++;

                    double logicalX = layer.XAxis.PhysicalVariantToNormal(pdata.GetXPhysical(originalRowIndex));
                    if (logicalX < minLogicalX)
                    {
                        minLogicalX = logicalX;
                    }
                    if (logicalX > maxLogicalX)
                    {
                        maxLogicalX = logicalX;
                    }

                    double logicalY = layer.YAxis.PhysicalVariantToNormal(pdata.GetXPhysical(originalRowIndex));
                    if (logicalY < minLogicalY)
                    {
                        minLogicalY = logicalY;
                    }
                    if (logicalY > maxLogicalY)
                    {
                        maxLogicalY = logicalY;
                    }
                }

                BarSizePosition3DGroupStyle.IntendToApply(externalGroups, localGroups, numberOfItems, minLogicalX, maxLogicalX, minLogicalY, maxLogicalY);
            }
            BarSizePosition3DGroupStyle bwp = PlotGroupStyle.GetStyleToInitialize <BarSizePosition3DGroupStyle>(externalGroups, localGroups);

            if (null != bwp)
            {
                bwp.Initialize(_barShiftStrategy, _barShiftMaxNumberOfItemsInOneDirection, _relInnerGapX, _relOuterGapX, _relInnerGapY, _relOuterGapY);
            }

            if (!_independentColor) // else if is used here because fill color has precedence over frame color
            {
                ColorGroupStyle.PrepareStyle(externalGroups, localGroups, delegate()
                                             { return(_pen.Color); });
            }
        }
Пример #3
0
        public void PaintPreprocessing(IPaintContext paintContext, IPlotArea layer, PlotItemCollection coll)
        {
            if (!CanUseStyle(layer, coll, out var plotDataDict))
            {
                return;
            }
            else
            {
                paintContext.AddValue(this, plotDataDict);
            }

            AltaxoVariant[] vArray = null;
            // First, add up all items since we start always with the last item
            int idx = -1;
            Processed3DPlotData previousItemData = null;

            foreach (IGPlotItem pi in coll)
            {
                if (pi is G3DPlotItem)
                {
                    idx++;

                    var gpi = pi as G3DPlotItem;
                    Processed3DPlotData pdata = plotDataDict[gpi];
                    if (null == pdata)
                    {
                        continue;
                    }

                    vArray = AddUp(vArray, pdata);

                    if (idx > 0) // this is not the first item
                    {
                        int j = -1;
                        foreach (int originalIndex in pdata.RangeList.OriginalRowIndices())
                        {
                            j++;
                            var rel = new Logical3D(
                                layer.XAxis.PhysicalVariantToNormal(pdata.GetXPhysical(originalIndex)),
                                layer.YAxis.PhysicalVariantToNormal(pdata.GetYPhysical(originalIndex)),
                                layer.ZAxis.PhysicalVariantToNormal(vArray[j]));

                            layer.CoordinateSystem.LogicalToLayerCoordinates(rel, out var pabs);
                            pdata.PlotPointsInAbsoluteLayerCoordinates[j] = pabs;
                        }
                    }

                    // we have also to exchange the accessor for the physical y value and replace it by our own one
                    var localArray       = (AltaxoVariant[])vArray.Clone();
                    var localArrayHolder = new LocalArrayHolder(localArray, pdata);
                    pdata.ZPhysicalAccessor = localArrayHolder.GetPhysical;
                    pdata.PreviousItemData  = previousItemData;
                    previousItemData        = pdata;
                }
            }
        }
Пример #4
0
        public void Paint(IGraphicsContext3D g, IPlotArea layer, Processed3DPlotData pdata, Processed3DPlotData prevItemData, Processed3DPlotData nextItemData)
        {
            if (null == pdata)
            {
                throw new ArgumentNullException(nameof(pdata));
            }

            PlotRangeList rangeList = pdata.RangeList;
            var           ptArray   = pdata.PlotPointsInAbsoluteLayerCoordinates;

            layer.CoordinateSystem.LogicalToLayerCoordinates(new Logical3D(0, 0, 0), out var leftFrontBotton);
            layer.CoordinateSystem.LogicalToLayerCoordinates(new Logical3D(1, 1, 1), out var rightBackTop);

            double globalBaseValue;

            if (_usePhysicalBaseValue)
            {
                globalBaseValue = layer.ZAxis.PhysicalVariantToNormal(_baseValue);
                if (double.IsNaN(globalBaseValue))
                {
                    globalBaseValue = 0;
                }
            }
            else
            {
                globalBaseValue = _baseValue.ToDouble();
            }

            bool useVariableColor = null != _cachedColorForIndexFunction && !_independentColor;

            var pen = _pen;

            int j = -1;

            foreach (int originalRowIndex in pdata.RangeList.OriginalRowIndices())
            {
                j++;

                double xCenterLogical = layer.XAxis.PhysicalVariantToNormal(pdata.GetXPhysical(originalRowIndex));
                double xLowerLogical  = xCenterLogical + _xOffsetLogical;
                double xUpperLogical  = xLowerLogical + _xSizeLogical;

                double yCenterLogical = layer.YAxis.PhysicalVariantToNormal(pdata.GetYPhysical(originalRowIndex));
                double yLowerLogical  = yCenterLogical + _yOffsetLogical;
                double yUpperLogical  = yLowerLogical + _ySizeLogical;

                double zCenterLogical = layer.ZAxis.PhysicalVariantToNormal(pdata.GetZPhysical(originalRowIndex));
                double zBaseLogical   = globalBaseValue;

                if (_startAtPreviousItem && pdata.PreviousItemData != null)
                {
                    double prevstart = layer.ZAxis.PhysicalVariantToNormal(pdata.PreviousItemData.GetZPhysical(originalRowIndex));
                    if (!double.IsNaN(prevstart))
                    {
                        zBaseLogical  = prevstart;
                        zBaseLogical += Math.Sign(zBaseLogical - globalBaseValue) * _previousItemZGap;
                    }
                }

                layer.CoordinateSystem.LogicalToLayerCoordinates(new Logical3D(xLowerLogical, yCenterLogical, zBaseLogical), out var lcp);
                layer.CoordinateSystem.LogicalToLayerCoordinates(new Logical3D(xUpperLogical, yCenterLogical, zBaseLogical), out var ucp);
                layer.CoordinateSystem.LogicalToLayerCoordinates(new Logical3D(xCenterLogical, yLowerLogical, zBaseLogical), out var clp);
                layer.CoordinateSystem.LogicalToLayerCoordinates(new Logical3D(xCenterLogical, yUpperLogical, zBaseLogical), out var cup);

                double penWidth1 = (lcp - ucp).Length;
                double penWidth2 = (clp - cup).Length;

                if (_useUniformCrossSectionThickness)
                {
                    pen = pen.WithUniformThickness(Math.Min(penWidth1, penWidth2));
                }
                else
                {
                    pen = pen.WithThickness1(penWidth1);
                    pen = pen.WithThickness2(penWidth2);
                }

                if (useVariableColor)
                {
                    pen = pen.WithColor(GdiColorHelper.ToNamedColor(_cachedColorForIndexFunction(originalRowIndex), "VariableColor"));
                }

                var isoLine = layer.CoordinateSystem.GetIsoline(new Logical3D(xLowerLogical, yLowerLogical, zBaseLogical), new Logical3D(xLowerLogical, yLowerLogical, zCenterLogical));
                g.DrawLine(pen, isoLine);
            }
        }
Пример #5
0
		public void Paint(IGraphicsContext3D g, IPlotArea layer, Processed3DPlotData pdata, Processed3DPlotData prevItemData, Processed3DPlotData nextItemData)
		{
			PlotRangeList rangeList = pdata.RangeList;
			var ptArray = pdata.PlotPointsInAbsoluteLayerCoordinates;

			// paint the style

			PointD3D leftFrontBotton, rightBackTop;
			layer.CoordinateSystem.LogicalToLayerCoordinates(new Logical3D(0, 0, 0), out leftFrontBotton);
			layer.CoordinateSystem.LogicalToLayerCoordinates(new Logical3D(1, 1, 1), out rightBackTop);

			double globalBaseValue;
			if (_usePhysicalBaseValue)
			{
				globalBaseValue = layer.ZAxis.PhysicalVariantToNormal(_baseValue);
				if (double.IsNaN(globalBaseValue))
					globalBaseValue = 0;
			}
			else
			{
				globalBaseValue = _baseValue.ToDouble();
			}

			bool useVariableColor = null != _cachedColorForIndexFunction && !_independentColor;

			var pen = _pen;

			int j = -1;
			foreach (int originalRowIndex in pdata.RangeList.OriginalRowIndices())
			{
				j++;

				double xCenterLogical = layer.XAxis.PhysicalVariantToNormal(pdata.GetXPhysical(originalRowIndex));
				double xLowerLogical = xCenterLogical + _xOffsetLogical;
				double xUpperLogical = xLowerLogical + _xSizeLogical;

				double yCenterLogical = layer.YAxis.PhysicalVariantToNormal(pdata.GetYPhysical(originalRowIndex));
				double yLowerLogical = yCenterLogical + _yOffsetLogical;
				double yUpperLogical = yLowerLogical + _ySizeLogical;

				double zCenterLogical = layer.ZAxis.PhysicalVariantToNormal(pdata.GetZPhysical(originalRowIndex));
				double zBaseLogical = globalBaseValue;

				if (_startAtPreviousItem && pdata.PreviousItemData != null)
				{
					double prevstart = layer.ZAxis.PhysicalVariantToNormal(pdata.PreviousItemData.GetZPhysical(originalRowIndex));
					if (!double.IsNaN(prevstart))
					{
						zBaseLogical = prevstart;
						zBaseLogical += Math.Sign(zBaseLogical - globalBaseValue) * _previousItemZGap;
					}
				}

				// calculate the size at the base
				PointD3D lcp, ucp, clp, cup;
				layer.CoordinateSystem.LogicalToLayerCoordinates(new Logical3D(xLowerLogical, yCenterLogical, zBaseLogical), out lcp);
				layer.CoordinateSystem.LogicalToLayerCoordinates(new Logical3D(xUpperLogical, yCenterLogical, zBaseLogical), out ucp);
				layer.CoordinateSystem.LogicalToLayerCoordinates(new Logical3D(xCenterLogical, yLowerLogical, zBaseLogical), out clp);
				layer.CoordinateSystem.LogicalToLayerCoordinates(new Logical3D(xCenterLogical, yUpperLogical, zBaseLogical), out cup);

				double penWidth1 = (lcp - ucp).Length;
				double penWidth2 = (clp - cup).Length;

				if (_useUniformCrossSectionThickness)
				{
					pen = pen.WithUniformThickness(Math.Min(penWidth1, penWidth2));
				}
				else
				{
					pen = pen.WithThickness1(penWidth1);
					pen = pen.WithThickness2(penWidth2);
				}

				if (useVariableColor)
					pen = pen.WithColor(GdiColorHelper.ToNamedColor(_cachedColorForIndexFunction(originalRowIndex), "VariableColor"));

				var isoLine = layer.CoordinateSystem.GetIsoline(new Logical3D(xLowerLogical, yLowerLogical, zBaseLogical), new Logical3D(xLowerLogical, yLowerLogical, zCenterLogical));
				g.DrawLine(pen, isoLine);
			}
		}
Пример #6
0
		public void PrepareGroupStyles(PlotGroupStyleCollection externalGroups, PlotGroupStyleCollection localGroups, IPlotArea layer, Processed3DPlotData pdata)
		{
			// first, we have to calculate the span of logical values from the minimum logical value to the maximum logical value
			int numberOfItems = 0;

			if (null != pdata)
			{
				double minLogicalX = double.MaxValue;
				double maxLogicalX = double.MinValue;
				double minLogicalY = double.MaxValue;
				double maxLogicalY = double.MinValue;
				foreach (int originalRowIndex in pdata.RangeList.OriginalRowIndices())
				{
					numberOfItems++;

					double logicalX = layer.XAxis.PhysicalVariantToNormal(pdata.GetXPhysical(originalRowIndex));
					if (logicalX < minLogicalX)
						minLogicalX = logicalX;
					if (logicalX > maxLogicalX)
						maxLogicalX = logicalX;

					double logicalY = layer.YAxis.PhysicalVariantToNormal(pdata.GetXPhysical(originalRowIndex));
					if (logicalY < minLogicalY)
						minLogicalY = logicalY;
					if (logicalY > maxLogicalY)
						maxLogicalY = logicalY;
				}

				BarSizePosition3DGroupStyle.IntendToApply(externalGroups, localGroups, numberOfItems, minLogicalX, maxLogicalX, minLogicalY, maxLogicalY);
			}
			BarSizePosition3DGroupStyle bwp = PlotGroupStyle.GetStyleToInitialize<BarSizePosition3DGroupStyle>(externalGroups, localGroups);
			if (null != bwp)
				bwp.Initialize(_barShiftStrategy, _barShiftMaxNumberOfItemsInOneDirection, _relInnerGapX, _relOuterGapX, _relInnerGapY, _relOuterGapY);

			if (!_independentColor) // else if is used here because fill color has precedence over frame color
				ColorGroupStyle.PrepareStyle(externalGroups, localGroups, delegate () { return this._pen.Color; });
		}
Пример #7
0
		public void Paint(IGraphicsContext3D g, IPlotArea layer, Processed3DPlotData pdata, Processed3DPlotData prevItemData, Processed3DPlotData nextItemData)
		{
			const double logicalClampMinimum = -10;
			const double logicalClampMaximum = 11;

			// Plot error bars for the dependent variable (y)
			PlotRangeList rangeList = pdata.RangeList;
			var ptArray = pdata.PlotPointsInAbsoluteLayerCoordinates;
			var columnX = ColumnX;
			var columnY = ColumnY;
			var columnZ = ColumnZ;

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

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

			var strokePen = _strokePen;

			foreach (PlotRange r in rangeList)
			{
				int lower = r.LowerBound;
				int upper = r.UpperBound;
				int offset = r.OffsetToOriginal;

				for (int j = lower; j < upper; j += _skipFrequency)
				{
					int originalRow = j + offset;
					double symbolSize = null == _cachedSymbolSizeForIndexFunction ? _symbolSize : _cachedSymbolSizeForIndexFunction(originalRow);

					strokePen = strokePen.WithThickness1(_lineWidth1Offset + _lineWidth1Factor * symbolSize);
					strokePen = strokePen.WithThickness2(_lineWidth2Offset + _lineWidth2Factor * symbolSize);

					if (null != _cachedColorForIndexFunction)
						strokePen = strokePen.WithColor(GdiColorHelper.ToNamedColor(_cachedColorForIndexFunction(originalRow), "VariableColor"));
					if (null != strokePen.LineEndCap)
						strokePen = strokePen.WithLineEndCap(strokePen.LineEndCap.WithMinimumAbsoluteAndRelativeSize(symbolSize * _endCapSizeFactor + _endCapSizeOffset, 1 + 1E-6));

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

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

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

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

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

					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;

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

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

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

					g.DrawLine(strokePen, isoLine);
				}
			}
		}
Пример #8
0
        public void Paint(IGraphicsContext3D g, IPlotArea layer, Processed3DPlotData pdata, Processed3DPlotData prevItemData, Processed3DPlotData nextItemData)
        {
            const double logicalClampMinimum = -10;
            const double logicalClampMaximum = 11;

            // Plot error bars for the dependent variable (y)
            PlotRangeList rangeList = pdata.RangeList;
            var           ptArray   = pdata.PlotPointsInAbsoluteLayerCoordinates;
            var           columnX   = ColumnX;
            var           columnY   = ColumnY;
            var           columnZ   = ColumnZ;

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

            foreach (PlotRange r in rangeList)
            {
                int lower  = r.LowerBound;
                int upper  = r.UpperBound;
                int offset = r.OffsetToOriginal;

                for (int j = lower; j < upper; j += _skipFrequency)
                {
                    int    originalRow = j + offset;
                    double symbolSize  = null == _cachedSymbolSizeForIndexFunction ? _symbolSize : _cachedSymbolSizeForIndexFunction(originalRow);

                    strokePen = strokePen.WithThickness1(_lineWidth1Offset + _lineWidth1Factor * symbolSize);
                    strokePen = strokePen.WithThickness2(_lineWidth2Offset + _lineWidth2Factor * symbolSize);

                    if (null != _cachedColorForIndexFunction)
                    {
                        strokePen = strokePen.WithColor(GdiColorHelper.ToNamedColor(_cachedColorForIndexFunction(originalRow), "VariableColor"));
                    }
                    if (null != strokePen.LineEndCap)
                    {
                        strokePen = strokePen.WithLineEndCap(strokePen.LineEndCap.WithMinimumAbsoluteAndRelativeSize(symbolSize * _endCapSizeFactor + _endCapSizeOffset, 1 + 1E-6));
                    }

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

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

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

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

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

                    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;
                    }

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

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

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

                    g.DrawLine(strokePen, isoLine);
                }
            }
        }