public void Paint(IGraphicsContext3D g, IPlotArea layer, CSPlaneID plane, int axisnumber) { if (!_showGrid) { return; } Scale axis = layer.Scales[axisnumber]; TickSpacing ticking = layer.Scales[axisnumber].TickSpacing; var layerRect = new RectangleD3D(PointD3D.Empty, layer.Size); if (_showZeroOnly) { var var = new Altaxo.Data.AltaxoVariant(0.0); double rel = axis.PhysicalVariantToNormal(var); //_majorPen.SetEnvironment(layerRect, BrushX.GetEffectiveMaximumResolution(g, 1)); if (rel >= 0 && rel <= 1) { var logV = new Logical3D(); logV.SetR(plane.PerpendicularAxisNumber, plane.LogicalValue); logV.SetR(axisnumber, rel); var thirdAxisNumber = Logical3D.GetPerpendicularAxisNumber(plane.PerpendicularAxisNumber, axisnumber); var line = layer.CoordinateSystem.GetIsoline(logV.WithR(thirdAxisNumber, 0), logV.WithR(thirdAxisNumber, 1)); g.DrawLine(MajorPen, line); } } else { double[] ticks; if (_showMinor) { //_minorPen.SetEnvironment(layerRect, BrushX.GetEffectiveMaximumResolution(g, 1)); ticks = ticking.GetMinorTicksNormal(axis); for (int i = 0; i < ticks.Length; ++i) { var logV = new Logical3D(); logV.SetR(plane.PerpendicularAxisNumber, plane.LogicalValue); logV.SetR(axisnumber, ticks[i]); var thirdAxisNumber = Logical3D.GetPerpendicularAxisNumber(plane.PerpendicularAxisNumber, axisnumber); var line = layer.CoordinateSystem.GetIsoline(logV.WithR(thirdAxisNumber, 0), logV.WithR(thirdAxisNumber, 1)); g.DrawLine(MinorPen, line); } } //MajorPen.SetEnvironment(layerRect, BrushX.GetEffectiveMaximumResolution(g, 1)); ticks = ticking.GetMajorTicksNormal(axis); for (int i = 0; i < ticks.Length; ++i) { var logV = new Logical3D(); logV.SetR(plane.PerpendicularAxisNumber, plane.LogicalValue); logV.SetR(axisnumber, ticks[i]); var thirdAxisNumber = Logical3D.GetPerpendicularAxisNumber(plane.PerpendicularAxisNumber, axisnumber); var line = layer.CoordinateSystem.GetIsoline(logV.WithR(thirdAxisNumber, 0), logV.WithR(thirdAxisNumber, 1)); g.DrawLine(MajorPen, line); } } }
public virtual void PaintLine(IGraphicsContext3D g, PointD3D beg, PointD3D end) { if (null != _linePen) { g.DrawLine(_linePen, beg, end); } }
public override void Paint(IGraphicsContext3D g, IPaintContext context) { var gs = g.SaveGraphicsState(); g.PrependTransform(_transformation); g.DrawLine(_linePen, Bounds.Location, Bounds.LocationPlusSize); g.RestoreGraphicsState(gs); }
public RectangleD3D PaintSymbol(IGraphicsContext3D g, RectangleD3D bounds) { bounds = bounds.WithPadding(0, 0, -bounds.SizeZ / 4); var heightBy2 = new VectorD3D(0, 0, bounds.SizeZ / 4); g.DrawLine(_pen, bounds.Center - heightBy2, bounds.Center + heightBy2); return(bounds); }
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); } }
public RectangleD3D PaintSymbol(IGraphicsContext3D g, RectangleD3D bounds) { bounds = bounds.WithPadding(0, 0, -bounds.SizeZ / 4); var heightBy2 = new VectorD3D(0, 0, bounds.SizeZ / 4); g.DrawLine(_pen, bounds.Center - heightBy2, bounds.Center + heightBy2); return bounds; }
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); } }
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); } } }
public void Paint(IGraphicsContext3D g, IPlotArea layer, CSPlaneID plane, int axisnumber) { if (!_showGrid) return; Scale axis = layer.Scales[axisnumber]; TickSpacing ticking = layer.Scales[axisnumber].TickSpacing; RectangleD3D layerRect = new RectangleD3D(PointD3D.Empty, layer.Size); if (_showZeroOnly) { Altaxo.Data.AltaxoVariant var = new Altaxo.Data.AltaxoVariant(0.0); double rel = axis.PhysicalVariantToNormal(var); //_majorPen.SetEnvironment(layerRect, BrushX.GetEffectiveMaximumResolution(g, 1)); if (rel >= 0 && rel <= 1) { Logical3D logV = new Logical3D(); logV.SetR(plane.PerpendicularAxisNumber, plane.LogicalValue); logV.SetR(axisnumber, rel); var thirdAxisNumber = Logical3D.GetPerpendicularAxisNumber(plane.PerpendicularAxisNumber, axisnumber); var line = layer.CoordinateSystem.GetIsoline(logV.WithR(thirdAxisNumber, 0), logV.WithR(thirdAxisNumber, 1)); g.DrawLine(MajorPen, line); } } else { double[] ticks; if (_showMinor) { //_minorPen.SetEnvironment(layerRect, BrushX.GetEffectiveMaximumResolution(g, 1)); ticks = ticking.GetMinorTicksNormal(axis); for (int i = 0; i < ticks.Length; ++i) { Logical3D logV = new Logical3D(); logV.SetR(plane.PerpendicularAxisNumber, plane.LogicalValue); logV.SetR(axisnumber, ticks[i]); var thirdAxisNumber = Logical3D.GetPerpendicularAxisNumber(plane.PerpendicularAxisNumber, axisnumber); var line = layer.CoordinateSystem.GetIsoline(logV.WithR(thirdAxisNumber, 0), logV.WithR(thirdAxisNumber, 1)); g.DrawLine(MinorPen, line); } } //MajorPen.SetEnvironment(layerRect, BrushX.GetEffectiveMaximumResolution(g, 1)); ticks = ticking.GetMajorTicksNormal(axis); for (int i = 0; i < ticks.Length; ++i) { Logical3D logV = new Logical3D(); logV.SetR(plane.PerpendicularAxisNumber, plane.LogicalValue); logV.SetR(axisnumber, ticks[i]); var thirdAxisNumber = Logical3D.GetPerpendicularAxisNumber(plane.PerpendicularAxisNumber, axisnumber); var line = layer.CoordinateSystem.GetIsoline(logV.WithR(thirdAxisNumber, 0), logV.WithR(thirdAxisNumber, 1)); g.DrawLine(MajorPen, line); } } }
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); } } }
public void Paint(IGraphicsContext3D g, IPlotArea layer, Processed3DPlotData pdata, Processed3DPlotData prevItemData, Processed3DPlotData nextItemData) { PlotRangeList rangeList = pdata.RangeList; var ptArray = pdata.PlotPointsInAbsoluteLayerCoordinates; // adjust the skip frequency if it was not set appropriate if (_skipFreq <= 0) { _skipFreq = 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; if (null == _cachedSymbolSizeForIndexFunction && null == _cachedColorForIndexFunction) // using a constant symbol size and constant color { var pen = _pen; // update pen widths double w1 = _lineWidth1Offset + _lineWidth1Factor * _cachedSymbolSize; double w2 = _lineWidth2Offset + _lineWidth2Factor * _cachedSymbolSize; pen = pen.WithThickness1(w1).WithThickness2(w2); var gapStart = 0.5 * (_gapAtStartOffset + _gapAtStartFactor * _cachedSymbolSize); var gapEnd = 0.5 * (_gapAtEndOffset + _gapAtEndFactor * _cachedSymbolSize); for (int r = 0; r < rangeList.Count; r++) { var range = rangeList[r]; int lower = range.LowerBound; int upper = range.UpperBound; for (int j = lower; j < upper; j += _skipFreq) { Logical3D r3d = layer.GetLogical3D(pdata, j + range.OffsetToOriginal); foreach (CSPlaneID id in dropTargets) { layer.CoordinateSystem.GetIsolineFromPointToPlane(r3d, id, out var isoLine); if (gapStart != 0 || gapEnd != 0) { isoLine = isoLine.ShortenedBy(RADouble.NewAbs(gapStart), RADouble.NewAbs(gapEnd)); } if (null != isoLine) { g.DrawLine(pen, isoLine); } } } } // for each range } else // using a variable symbol size or variable symbol color { for (int r = 0; r < rangeList.Count; r++) { var range = rangeList[r]; int lower = range.LowerBound; int upper = range.UpperBound; int offset = range.OffsetToOriginal; for (int j = lower; j < upper; j += _skipFreq) { var pen = _pen; if (null == _cachedColorForIndexFunction) { _cachedSymbolSize = _cachedSymbolSizeForIndexFunction(j + offset); double w1 = _lineWidth1Offset + _lineWidth1Factor * _cachedSymbolSize; double w2 = _lineWidth2Offset + _lineWidth2Factor * _cachedSymbolSize; pen = _pen.WithThickness1(w1).WithThickness2(w2); } else { _cachedSymbolSize = null == _cachedSymbolSizeForIndexFunction ? _cachedSymbolSize : _cachedSymbolSizeForIndexFunction(j + offset); double w1 = _lineWidth1Offset + _lineWidth1Factor * _cachedSymbolSize; double w2 = _lineWidth2Offset + _lineWidth2Factor * _cachedSymbolSize; var customSymbolColor = _cachedColorForIndexFunction(j + offset); pen = _pen.WithThickness1(w1).WithThickness2(w2).WithColor(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, j + rangeList[r].OffsetToOriginal); foreach (CSPlaneID id in _dropTargets) { layer.CoordinateSystem.GetIsolineFromPointToPlane(r3d, id, out var isoLine); if (gapStart != 0 || gapEnd != 0) { isoLine = isoLine.ShortenedBy(RADouble.NewAbs(gapStart), RADouble.NewAbs(gapEnd)); } if (null != isoLine) { g.DrawLine(pen, isoLine); } } } } } }
/// <summary> /// Paint the axis in the Graphics context. /// </summary> /// <param name="g">The graphics context painting to.</param> /// <param name="layer">The layer the axis belongs to.</param> /// <param name="styleInfo">The axis information of the axis to paint.</param> /// <param name="customTickSpacing">If not <c>null</c>, this parameter provides a custom tick spacing that is used instead of the default tick spacing of the scale.</param> public void Paint(IGraphicsContext3D g, IPlotArea layer, CSAxisInformation styleInfo, TickSpacing customTickSpacing) { CSLineID styleID = styleInfo.Identifier; _cachedAxisStyleInfo = styleInfo; Scale axis = layer.Scales[styleID.ParallelAxisNumber]; TickSpacing ticking = null != customTickSpacing ? customTickSpacing : layer.Scales[styleID.ParallelAxisNumber].TickSpacing; Logical3D r0 = styleID.GetLogicalPoint(styleInfo.LogicalValueAxisOrg); Logical3D r1 = styleID.GetLogicalPoint(styleInfo.LogicalValueAxisEnd); var sweepPath = layer.CoordinateSystem.GetIsoline(r0, r1); g.DrawLine(_axisPen, sweepPath); _cachedMainLinePointsUsedForHitTesting = sweepPath.Points.ToArray(); var majorTickLinesUsedForHitTesting = new List<LineD3D>(); var minorTickLinesUsedForHitTesting = new List<LineD3D>(); Logical3D outer; // now the major ticks VectorD3D outVector; double[] majorticks = ticking.GetMajorTicksNormal(axis); for (int i = 0; i < majorticks.Length; i++) { double r = majorticks[i]; if (_showFirstUpMajorTicks) { outer = layer.CoordinateSystem.GetLogicalDirection(styleID.ParallelAxisNumber, CSAxisSide.FirstUp); var tickorg = layer.CoordinateSystem.GetPositionAndNormalizedDirection(r0, r1, r, outer, out outVector); var tickend = tickorg + outVector * _majorTickLength; g.DrawLine(_majorTickPen, tickorg, tickend); majorTickLinesUsedForHitTesting.Add(new LineD3D(tickorg, tickend)); } if (_showFirstDownMajorTicks) { outer = layer.CoordinateSystem.GetLogicalDirection(styleID.ParallelAxisNumber, CSAxisSide.FirstDown); var tickorg = layer.CoordinateSystem.GetPositionAndNormalizedDirection(r0, r1, r, outer, out outVector); var tickend = tickorg + outVector * _majorTickLength; g.DrawLine(_majorTickPen, tickorg, tickend); majorTickLinesUsedForHitTesting.Add(new LineD3D(tickorg, tickend)); } if (_showSecondUpMajorTicks) { outer = layer.CoordinateSystem.GetLogicalDirection(styleID.ParallelAxisNumber, CSAxisSide.SecondUp); var tickorg = layer.CoordinateSystem.GetPositionAndNormalizedDirection(r0, r1, r, outer, out outVector); var tickend = tickorg + outVector * _majorTickLength; g.DrawLine(_majorTickPen, tickorg, tickend); majorTickLinesUsedForHitTesting.Add(new LineD3D(tickorg, tickend)); } if (_showSecondDownMajorTicks) { outer = layer.CoordinateSystem.GetLogicalDirection(styleID.ParallelAxisNumber, CSAxisSide.SecondDown); var tickorg = layer.CoordinateSystem.GetPositionAndNormalizedDirection(r0, r1, r, outer, out outVector); var tickend = tickorg + outVector * _majorTickLength; g.DrawLine(_majorTickPen, tickorg, tickend); majorTickLinesUsedForHitTesting.Add(new LineD3D(tickorg, tickend)); } } // now the major ticks double[] minorticks = ticking.GetMinorTicksNormal(axis); for (int i = 0; i < minorticks.Length; i++) { double r = minorticks[i]; if (_showFirstUpMinorTicks) { outer = layer.CoordinateSystem.GetLogicalDirection(styleID.ParallelAxisNumber, CSAxisSide.FirstUp); var tickorg = layer.CoordinateSystem.GetPositionAndNormalizedDirection(r0, r1, r, outer, out outVector); var tickend = tickorg + outVector * _minorTickLength; g.DrawLine(_minorTickPen, tickorg, tickend); minorTickLinesUsedForHitTesting.Add(new LineD3D(tickorg, tickend)); } if (_showFirstDownMinorTicks) { outer = layer.CoordinateSystem.GetLogicalDirection(styleID.ParallelAxisNumber, CSAxisSide.FirstDown); var tickorg = layer.CoordinateSystem.GetPositionAndNormalizedDirection(r0, r1, r, outer, out outVector); var tickend = tickorg + outVector * _minorTickLength; g.DrawLine(_minorTickPen, tickorg, tickend); minorTickLinesUsedForHitTesting.Add(new LineD3D(tickorg, tickend)); } if (_showSecondUpMinorTicks) { outer = layer.CoordinateSystem.GetLogicalDirection(styleID.ParallelAxisNumber, CSAxisSide.SecondUp); var tickorg = layer.CoordinateSystem.GetPositionAndNormalizedDirection(r0, r1, r, outer, out outVector); var tickend = tickorg + outVector * _minorTickLength; g.DrawLine(_minorTickPen, tickorg, tickend); minorTickLinesUsedForHitTesting.Add(new LineD3D(tickorg, tickend)); } if (_showSecondDownMinorTicks) { outer = layer.CoordinateSystem.GetLogicalDirection(styleID.ParallelAxisNumber, CSAxisSide.SecondDown); var tickorg = layer.CoordinateSystem.GetPositionAndNormalizedDirection(r0, r1, r, outer, out outVector); var tickend = tickorg + outVector * _minorTickLength; g.DrawLine(_minorTickPen, tickorg, tickend); minorTickLinesUsedForHitTesting.Add(new LineD3D(tickorg, tickend)); } } _cachedMajorTickLinesUsedForHitTesting = majorTickLinesUsedForHitTesting.ToArray(); _cachedMinorTickLinesUsedForHitTesting = minorTickLinesUsedForHitTesting.ToArray(); }
/// <summary> /// Template to make a line draw. /// </summary> /// <param name="g">Graphics context.</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="pen">The pen to draw the line.</param> /// <param name="symbolGap">The size of the symbol gap. Argument is the original index of the data. The return value is the absolute symbol gap at this index. This function is null if no symbol gap is required.</param> /// <param name="skipFrequency">Skip frequency. Normally 1, thus all gaps are taken into account. If 2, only every 2nd gap is taken into account, and so on.</param> /// <param name="connectCircular">If true, the end of the line is connected with the start of the line.</param> public override void Paint( IGraphicsContext3D g, Processed3DPlotData pdata, PlotRange range, IPlotArea layer, PenX3D pen, Func <int, double> symbolGap, int skipFrequency, bool connectCircular) { var linePoints = pdata.PlotPointsInAbsoluteLayerCoordinates; var linepts = new PointD3D[range.Length + (connectCircular ? 1 : 0)]; Array.Copy(linePoints, range.LowerBound, linepts, 0, range.Length); // Extract if (connectCircular) { linepts[linepts.Length - 1] = linepts[0]; } int lastIdx = range.Length - 1 + (connectCircular ? 1 : 0); var layerSize = layer.Size; if (symbolGap != null) { if (skipFrequency <= 1) // skip all scatter symbol gaps -> thus skipOffset can be ignored { for (int i = 0; i < lastIdx; i++) { int originalIndex = range.OffsetToOriginal + i; var diff = linepts[i + 1] - linepts[i]; double gapAtStart = symbolGap(originalIndex); double gapAtEnd = i != (range.Length - 1) ? symbolGap(originalIndex + 1) : symbolGap(range.OffsetToOriginal); var relAtStart = 0.5 * gapAtStart / diff.Length; // 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 = 0.5 * gapAtEnd / diff.Length; // 0.5 because symbolGap is the full gap between two lines, thus between the symbol center and the beginning of the line it is only 1/2 if ((relAtStart + relAtEnd) < 1) // a line only appears if sum of the gaps is smaller than 1 { var start = linepts[i] + relAtStart * diff; var stop = linepts[i + 1] - relAtEnd * diff; g.DrawLine(pen, start, stop); } } // end for } // skipFrequency was 1 else // skipFrequency is > 1 { for (int i = 0; i < lastIdx; i += skipFrequency) { int originalRowIndex = range.OriginalFirstPoint + i; double gapAtStart = symbolGap(originalRowIndex); double gapAtEnd = i != range.Length ? symbolGap(originalRowIndex + skipFrequency) : symbolGap(range.OffsetToOriginal); IPolylineD3D polyline = SharpPolylineD3D.FromPointsWithPossibleDublettes(linepts.Skip(i).Take(1 + skipFrequency)); polyline = polyline.ShortenedBy(RADouble.NewAbs(gapAtStart / 2), RADouble.NewAbs(gapAtEnd / 2)); if (null != polyline) { g.DrawLine(pen, polyline); } } // end for. } } else // no line symbol gap required, so we can use DrawLines to draw the lines { if (linepts.Length > 1) // we don't want to have a drawing exception if number of points is only one { g.DrawLine(pen, SharpPolylineD3D.FromPointsWithPossibleDublettes(linepts)); } } }
/// <summary> /// Paint the axis in the Graphics context. /// </summary> /// <param name="g">The graphics context painting to.</param> /// <param name="layer">The layer the axis belongs to.</param> /// <param name="styleInfo">The axis information of the axis to paint.</param> /// <param name="customTickSpacing">If not <c>null</c>, this parameter provides a custom tick spacing that is used instead of the default tick spacing of the scale.</param> public void Paint(IGraphicsContext3D g, IPlotArea layer, CSAxisInformation styleInfo, TickSpacing customTickSpacing) { CSLineID styleID = styleInfo.Identifier; _cachedAxisStyleInfo = styleInfo; Scale axis = layer.Scales[styleID.ParallelAxisNumber]; TickSpacing ticking = null != customTickSpacing ? customTickSpacing : layer.Scales[styleID.ParallelAxisNumber].TickSpacing; Logical3D r0 = styleID.GetLogicalPoint(styleInfo.LogicalValueAxisOrg); Logical3D r1 = styleID.GetLogicalPoint(styleInfo.LogicalValueAxisEnd); var sweepPath = layer.CoordinateSystem.GetIsoline(r0, r1); g.DrawLine(_axisPen, sweepPath); _cachedMainLinePointsUsedForHitTesting = sweepPath.Points.ToArray(); var majorTickLinesUsedForHitTesting = new List <LineD3D>(); var minorTickLinesUsedForHitTesting = new List <LineD3D>(); Logical3D outer; // now the major ticks VectorD3D outVector; double[] majorticks = ticking.GetMajorTicksNormal(axis); for (int i = 0; i < majorticks.Length; i++) { double r = majorticks[i]; if (_showFirstUpMajorTicks) { outer = layer.CoordinateSystem.GetLogicalDirection(styleID.ParallelAxisNumber, CSAxisSide.FirstUp); var tickorg = layer.CoordinateSystem.GetPositionAndNormalizedDirection(r0, r1, r, outer, out outVector); var tickend = tickorg + outVector * _majorTickLength; g.DrawLine(_majorTickPen, tickorg, tickend); majorTickLinesUsedForHitTesting.Add(new LineD3D(tickorg, tickend)); } if (_showFirstDownMajorTicks) { outer = layer.CoordinateSystem.GetLogicalDirection(styleID.ParallelAxisNumber, CSAxisSide.FirstDown); var tickorg = layer.CoordinateSystem.GetPositionAndNormalizedDirection(r0, r1, r, outer, out outVector); var tickend = tickorg + outVector * _majorTickLength; g.DrawLine(_majorTickPen, tickorg, tickend); majorTickLinesUsedForHitTesting.Add(new LineD3D(tickorg, tickend)); } if (_showSecondUpMajorTicks) { outer = layer.CoordinateSystem.GetLogicalDirection(styleID.ParallelAxisNumber, CSAxisSide.SecondUp); var tickorg = layer.CoordinateSystem.GetPositionAndNormalizedDirection(r0, r1, r, outer, out outVector); var tickend = tickorg + outVector * _majorTickLength; g.DrawLine(_majorTickPen, tickorg, tickend); majorTickLinesUsedForHitTesting.Add(new LineD3D(tickorg, tickend)); } if (_showSecondDownMajorTicks) { outer = layer.CoordinateSystem.GetLogicalDirection(styleID.ParallelAxisNumber, CSAxisSide.SecondDown); var tickorg = layer.CoordinateSystem.GetPositionAndNormalizedDirection(r0, r1, r, outer, out outVector); var tickend = tickorg + outVector * _majorTickLength; g.DrawLine(_majorTickPen, tickorg, tickend); majorTickLinesUsedForHitTesting.Add(new LineD3D(tickorg, tickend)); } } // now the major ticks double[] minorticks = ticking.GetMinorTicksNormal(axis); for (int i = 0; i < minorticks.Length; i++) { double r = minorticks[i]; if (_showFirstUpMinorTicks) { outer = layer.CoordinateSystem.GetLogicalDirection(styleID.ParallelAxisNumber, CSAxisSide.FirstUp); var tickorg = layer.CoordinateSystem.GetPositionAndNormalizedDirection(r0, r1, r, outer, out outVector); var tickend = tickorg + outVector * _minorTickLength; g.DrawLine(_minorTickPen, tickorg, tickend); minorTickLinesUsedForHitTesting.Add(new LineD3D(tickorg, tickend)); } if (_showFirstDownMinorTicks) { outer = layer.CoordinateSystem.GetLogicalDirection(styleID.ParallelAxisNumber, CSAxisSide.FirstDown); var tickorg = layer.CoordinateSystem.GetPositionAndNormalizedDirection(r0, r1, r, outer, out outVector); var tickend = tickorg + outVector * _minorTickLength; g.DrawLine(_minorTickPen, tickorg, tickend); minorTickLinesUsedForHitTesting.Add(new LineD3D(tickorg, tickend)); } if (_showSecondUpMinorTicks) { outer = layer.CoordinateSystem.GetLogicalDirection(styleID.ParallelAxisNumber, CSAxisSide.SecondUp); var tickorg = layer.CoordinateSystem.GetPositionAndNormalizedDirection(r0, r1, r, outer, out outVector); var tickend = tickorg + outVector * _minorTickLength; g.DrawLine(_minorTickPen, tickorg, tickend); minorTickLinesUsedForHitTesting.Add(new LineD3D(tickorg, tickend)); } if (_showSecondDownMinorTicks) { outer = layer.CoordinateSystem.GetLogicalDirection(styleID.ParallelAxisNumber, CSAxisSide.SecondDown); var tickorg = layer.CoordinateSystem.GetPositionAndNormalizedDirection(r0, r1, r, outer, out outVector); var tickend = tickorg + outVector * _minorTickLength; g.DrawLine(_minorTickPen, tickorg, tickend); minorTickLinesUsedForHitTesting.Add(new LineD3D(tickorg, tickend)); } } _cachedMajorTickLinesUsedForHitTesting = majorTickLinesUsedForHitTesting.ToArray(); _cachedMinorTickLinesUsedForHitTesting = minorTickLinesUsedForHitTesting.ToArray(); }
public void Paint(IGraphicsContext3D g, IPlotArea layer, Processed3DPlotData pdata, Processed3DPlotData prevItemData, Processed3DPlotData nextItemData) { PlotRangeList rangeList = pdata.RangeList; var ptArray = pdata.PlotPointsInAbsoluteLayerCoordinates; // adjust the skip frequency if it was not set appropriate if (_skipFreq <= 0) _skipFreq = 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; if (null == _cachedSymbolSizeForIndexFunction && null == _cachedColorForIndexFunction) // using a constant symbol size and constant color { var pen = _pen; // update pen widths double w1 = _lineWidth1Offset + _lineWidth1Factor * _cachedSymbolSize; double w2 = _lineWidth2Offset + _lineWidth2Factor * _cachedSymbolSize; pen = pen.WithThickness1(w1).WithThickness2(w2); var gapStart = 0.5 * (_gapAtStartOffset + _gapAtStartFactor * _cachedSymbolSize); var gapEnd = 0.5 * (_gapAtEndOffset + _gapAtEndFactor * _cachedSymbolSize); for (int r = 0; r < rangeList.Count; r++) { var range = rangeList[r]; int lower = range.LowerBound; int upper = range.UpperBound; for (int j = lower; j < upper; j += _skipFreq) { Logical3D r3d = layer.GetLogical3D(pdata, j + range.OffsetToOriginal); foreach (CSPlaneID id in dropTargets) { IPolylineD3D isoLine; layer.CoordinateSystem.GetIsolineFromPointToPlane(r3d, id, out isoLine); if (gapStart != 0 || gapEnd != 0) isoLine = isoLine.ShortenedBy(RADouble.NewAbs(gapStart), RADouble.NewAbs(gapEnd)); if (null != isoLine) g.DrawLine(pen, isoLine); } } } // for each range } else // using a variable symbol size or variable symbol color { for (int r = 0; r < rangeList.Count; r++) { var range = rangeList[r]; int lower = range.LowerBound; int upper = range.UpperBound; int offset = range.OffsetToOriginal; for (int j = lower; j < upper; j += _skipFreq) { var pen = _pen; if (null == _cachedColorForIndexFunction) { _cachedSymbolSize = _cachedSymbolSizeForIndexFunction(j + offset); double w1 = _lineWidth1Offset + _lineWidth1Factor * _cachedSymbolSize; double w2 = _lineWidth2Offset + _lineWidth2Factor * _cachedSymbolSize; pen = _pen.WithThickness1(w1).WithThickness2(w2); } else { _cachedSymbolSize = null == _cachedSymbolSizeForIndexFunction ? _cachedSymbolSize : _cachedSymbolSizeForIndexFunction(j + offset); double w1 = _lineWidth1Offset + _lineWidth1Factor * _cachedSymbolSize; double w2 = _lineWidth2Offset + _lineWidth2Factor * _cachedSymbolSize; var customSymbolColor = _cachedColorForIndexFunction(j + offset); pen = _pen.WithThickness1(w1).WithThickness2(w2).WithColor(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, j + rangeList[r].OffsetToOriginal); foreach (CSPlaneID id in _dropTargets) { IPolylineD3D isoLine; layer.CoordinateSystem.GetIsolineFromPointToPlane(r3d, id, out isoLine); if (gapStart != 0 || gapEnd != 0) isoLine = isoLine.ShortenedBy(RADouble.NewAbs(gapStart), RADouble.NewAbs(gapEnd)); if (null != isoLine) g.DrawLine(pen, isoLine); } } } } }
/// <summary> /// Template to make a line draw. /// </summary> /// <param name="g">Graphics context.</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="pen">The pen to draw the line.</param> /// <param name="symbolGap">The size of the symbol gap. Argument is the original index of the data. The return value is the absolute symbol gap at this index. This function is null if no symbol gap is required.</param> /// <param name="skipFrequency">Skip frequency. Normally 1, thus all gaps are taken into account. If 2, only every 2nd gap is taken into account, and so on.</param> /// <param name="connectCircular">If true, the end of the line is connected with the start of the line.</param> public override void Paint( IGraphicsContext3D g, Processed3DPlotData pdata, PlotRange range, IPlotArea layer, PenX3D pen, Func<int, double> symbolGap, int skipFrequency, bool connectCircular) { var linePoints = pdata.PlotPointsInAbsoluteLayerCoordinates; var linepts = new PointD3D[range.Length + (connectCircular ? 1 : 0)]; Array.Copy(linePoints, range.LowerBound, linepts, 0, range.Length); // Extract if (connectCircular) linepts[linepts.Length - 1] = linepts[0]; int lastIdx = range.Length - 1 + (connectCircular ? 1 : 0); var layerSize = layer.Size; if (symbolGap != null) { if (skipFrequency <= 1) // skip all scatter symbol gaps -> thus skipOffset can be ignored { for (int i = 0; i < lastIdx; i++) { int originalIndex = range.OffsetToOriginal + i; var diff = linepts[i + 1] - linepts[i]; double gapAtStart = symbolGap(originalIndex); double gapAtEnd = i != (range.Length-1) ? symbolGap(originalIndex + 1) : symbolGap(range.OffsetToOriginal); var relAtStart = 0.5 * gapAtStart / diff.Length; // 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 = 0.5 * gapAtEnd / diff.Length; // 0.5 because symbolGap is the full gap between two lines, thus between the symbol center and the beginning of the line it is only 1/2 if ((relAtStart + relAtEnd) < 1) // a line only appears if sum of the gaps is smaller than 1 { var start = linepts[i] + relAtStart * diff; var stop = linepts[i + 1] - relAtEnd * diff; g.DrawLine(pen, start, stop); } } // end for } // skipFrequency was 1 else // skipFrequency is > 1 { for (int i = 0; i < lastIdx; i += skipFrequency) { int originalRowIndex = range.OriginalFirstPoint + i; double gapAtStart = symbolGap(originalRowIndex); double gapAtEnd = i != range.Length ? symbolGap(originalRowIndex + skipFrequency) : symbolGap(range.OffsetToOriginal); IPolylineD3D polyline = SharpPolylineD3D.FromPointsWithPossibleDublettes(linepts.Skip(i).Take(1 + skipFrequency)); polyline = polyline.ShortenedBy(RADouble.NewAbs(gapAtStart / 2), RADouble.NewAbs(gapAtEnd / 2)); if (null != polyline) g.DrawLine(pen, polyline); } // end for. } } else // no line symbol gap required, so we can use DrawLines to draw the lines { if (linepts.Length > 1) // we don't want to have a drawing exception if number of points is only one { g.DrawLine(pen, SharpPolylineD3D.FromPointsWithPossibleDublettes(linepts)); } } }