internal RedarwHelper(Rectangle clientRectangle) { this.currentMinute = -1; this.nextMinute = -1; this.clientRectangle = clientRectangle; this.arcRect = clientRectangle; this.brushX = new SolidBrushX(Color.Red); this.penX = new PenX(Color.Gray, BORDER_WIDTH); this.linePenX = new PenX(Color.Black); this.gx = new GraphicsX(arcRect.Width, arcRect.Height); this.gxNextMinute = new GraphicsX(arcRect.Width, arcRect.Height); this.arcRect.Width--; this.arcRect.Height--; this.arcRect.Inflate(-25, -25); int delta = BORDER_WIDTH / 2; boarderRect = new Rectangle(arcRect.Left + delta, arcRect.Top + delta, arcRect.Width - BORDER_WIDTH, arcRect.Height - BORDER_WIDTH); this.boarderRect = this.arcRect; this.currentMinuteRedrawRect = clientRectangle; }
protected override IEnumerable <Main.DocumentNodeAndName> GetDocumentNodeChildrenWithName() { if (null != _pen) { yield return(new DocumentNodeAndName(_pen, () => _pen = null, "Pen")); } }
public void CopyFrom(ScatterPlotStyle from, bool suppressChangeEvent) { this._shape = from._shape; this._style = from._style; if (null == this._dropLine) { this._dropLine = new CSPlaneIDList(); } else { this._dropLine.Clear(); } this._dropLine.AddClonedRange(from._dropLine); this._pen = null == from._pen ? null : (PenX)from._pen.Clone(); this._independentColor = from._independentColor; this._independentSymbolSize = from._independentSymbolSize; this._symbolSize = from._symbolSize; this._relativePenWidth = from._relativePenWidth; this._skipFreq = from._skipFreq; this._cachedPath = null == from._cachedPath ? null : (GraphicsPath)from._cachedPath.Clone(); this._cachedFillPath = from._cachedFillPath; this._cachedFillBrush = null == from._cachedFillBrush ? null : (BrushX)from._cachedFillBrush.Clone(); this._parent = from._parent; if (!suppressChangeEvent) { OnChanged(); } }
public void CopyFrom(LinePlotStyle from, Main.EventFiring eventFiring) { if (object.ReferenceEquals(this, from)) { return; } using (var suspendToken = SuspendGetToken()) { _independentSkipFrequency = from._independentSkipFrequency; _skipFrequency = from._skipFrequency; _ignoreMissingDataPoints = from._ignoreMissingDataPoints; _independentOnShiftingGroupStyles = from._independentOnShiftingGroupStyles; _connectCircular = from._connectCircular; _connectionStyle = from._connectionStyle; _linePen = null == from._linePen ? null : from._linePen.Clone(); _independentDashStyle = from._independentDashStyle; _independentColor = from._independentColor; _independentSymbolSize = from._independentSymbolSize; _symbolSize = from._symbolSize; _useSymbolGap = from._useSymbolGap; _symbolGapOffset = from._symbolGapOffset; _symbolGapFactor = from._symbolGapFactor; EhSelfChanged(); suspendToken.Resume(eventFiring); } }
/// <summary> /// Creates a default axis style. /// </summary> public AxisLineStyle(Main.Properties.IReadOnlyPropertyBag context) { double penWidth = GraphDocument.GetDefaultPenWidth(context); double majorTickLength = GraphDocument.GetDefaultMajorTickLength(context); var color = GraphDocument.GetDefaultForeColor(context); _axisPen = new PenX(color, penWidth) { ParentObject = this }; _majorTickPen = new PenX(color, penWidth) { ParentObject = this }; _minorTickPen = new PenX(color, penWidth) { ParentObject = this }; _majorTickLength = majorTickLength; _minorTickLength = majorTickLength / 2; _showFirstUpMajorTicks = true; // true if right major ticks should be visible _showFirstDownMajorTicks = true; // true if left major ticks should be visible _showFirstUpMinorTicks = true; // true if right minor ticks should be visible _showFirstDownMinorTicks = true; // true if left minor ticks should be visible }
public ColorTypeThicknessPenController(PenX doc) { if (doc == null) { throw new ArgumentNullException("doc"); } _doc = doc; _tempDoc = (PenX)doc.Clone(); }
/// <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); } }
protected OpenPathShapeBase(ItemLocationDirect location, Altaxo.Main.Properties.IReadOnlyPropertyBag context) : base(location) { if (null == context) context = PropertyExtensions.GetPropertyContextOfProject(); var penWidth = GraphDocument.GetDefaultPenWidth(context); var foreColor = context.GetValue(GraphDocument.PropertyKeyDefaultForeColor); Pen = new PenX(foreColor, penWidth); }
/// <summary> /// Template to make a line draw. /// </summary> /// <param name="g">Graphics context.</param> /// <param name="allLinePoints">The plot data. Don't use the Range property of the pdata, since it is overriden by the next argument.</param> /// <param name="range">The plot range to use.</param> /// <param name="layer">Graphics layer.</param> /// <param name="pen">The pen to draw the line.</param> /// <param name="symbolGap">The size of the symbol gap. Argument is the original index of the data. The return value is the absolute symbol gap at this index. /// This function is null if no symbol gap is required.</param> /// <param name="skipFrequency">Skip frequency. Normally 1, thus all gaps are taken into account. If 2, only every 2nd gap is taken into account, and so on.</param> /// <param name="connectCircular">If true, the line is connected circular, and the area is the polygon inside of that circular connection.</param> /// <param name="linePlotStyle">The line plot style.</param> public abstract void PaintOneRange( Graphics g, PointF[] allLinePoints, IPlotRange range, IPlotArea layer, PenX pen, Func <int, double> symbolGap, int skipFrequency, bool connectCircular, LinePlotStyle linePlotStyle );
protected override void CopyFrom(GraphicBase bfrom) { ShapeGraphic from = bfrom as ShapeGraphic; if (from != null) { this._fillBrush = (BrushX)from._fillBrush.Clone(); this._linePen = (PenX)from._linePen.Clone(); } base.CopyFrom(bfrom); }
/// <summary> /// Template to make a line draw. /// </summary> /// <param name="g">Graphics context.</param> /// <param name="allLinePoints">The plot data. Don't use the Range property of the pdata, since it is overriden by the next argument.</param> /// <param name="range">The plot range to use.</param> /// <param name="layer">Graphics layer.</param> /// <param name="pen">The pen to draw the line.</param> /// <param name="symbolGap">The size of the symbol gap. Argument is the original index of the data. The return value is the absolute symbol gap at this index. /// This function is null if no symbol gap is required.</param> /// <param name="skipFrequency">Skip frequency. Normally 1, thus all gaps are taken into account. If 2, only every 2nd gap is taken into account, and so on.</param> /// <param name="connectCircular">If true, the line is connected circular, and the area is the polygon inside of that circular connection.</param> /// <param name="linePlotStyle">The line plot style.</param> public abstract void PaintOneRange( Graphics g, PointF[] allLinePoints, IPlotRange range, IPlotArea layer, PenX pen, Func<int, double> symbolGap, int skipFrequency, bool connectCircular, LinePlotStyle linePlotStyle );
private IEnumerable <Main.DocumentNodeAndName> GetMyDocumentNodeChildrenWithName() { if (null != _linePen) { yield return(new Main.DocumentNodeAndName(_linePen, () => _linePen = null, "LinePen")); } if (null != _fillBrush) { yield return(new Main.DocumentNodeAndName(_fillBrush, () => _fillBrush = null, "FillBrush")); } }
private IEnumerable <Main.DocumentNodeAndName> GetMyDocumentNodeChildrenWithName() { if (null != _linePen) { yield return(new Main.DocumentNodeAndName(_linePen, () => _linePen = null, "LinePen")); } if (null != _outlinePen) { yield return(new Main.DocumentNodeAndName(_outlinePen, () => _outlinePen = null, "OutlinePen")); } }
public bool CopyFrom(object obj, bool copyWithDataReferences) { if (object.ReferenceEquals(this, obj)) { return(true); } var from = obj as VectorCartesicPlotStyle; if (null != from) { _meaningOfValues = from._meaningOfValues; _independentSkipFrequency = from._independentSkipFrequency; _skipFrequency = from._skipFrequency; _ignoreMissingDataPoints = from._ignoreMissingDataPoints; _useManualVectorLength = from._useManualVectorLength; _vectorLengthOffset = from._vectorLengthOffset; _vectorLengthFactor = from._vectorLengthFactor; _independentSymbolSize = from._independentSymbolSize; _symbolSize = from._symbolSize; _strokePen = from._strokePen; _independentColor = from._independentColor; _lineWidth1Offset = from._lineWidth1Offset; _lineWidth1Factor = from._lineWidth1Factor; _endCapSizeFactor = from._endCapSizeFactor; _endCapSizeOffset = from._endCapSizeOffset; _useSymbolGap = from._useSymbolGap; _symbolGapFactor = from._symbolGapFactor; _symbolGapOffset = from._symbolGapOffset; _independentSkipFrequency = from._independentSkipFrequency; _skipFrequency = from._skipFrequency; _independentOnShiftingGroupStyles = from._independentOnShiftingGroupStyles; _cachedLogicalShiftX = from._cachedLogicalShiftX; _cachedLogicalShiftY = from._cachedLogicalShiftY; if (copyWithDataReferences) { ChildCloneToMember(ref _columnX, from._columnX); ChildCloneToMember(ref _columnY, from._columnY); } EhSelfChanged(); return(true); } return(false); }
public DropLinePlotStyle(IEnumerable <CSPlaneID> planeIDs, PenX pen) { if (null == pen) { throw new ArgumentNullException(nameof(pen)); } ChildSetMember(ref _pen, pen); _dropTargets = new CSPlaneIDList(planeIDs); // Cached values SetCachedValues(); }
protected OpenPathShapeBase(ItemLocationDirect location, Altaxo.Main.Properties.IReadOnlyPropertyBag context) : base(location) { if (null == context) { context = PropertyExtensions.GetPropertyContextOfProject(); } var penWidth = GraphDocument.GetDefaultPenWidth(context); var foreColor = context.GetValue(GraphDocument.PropertyKeyDefaultForeColor); Pen = new PenX(foreColor, penWidth); }
/// <summary> /// Template to make a line draw. /// </summary> /// <param name="g">Graphics context.</param> /// <param name="allLinePoints">The plot data. Don't use the Range property of the pdata, since it is overriden by the next argument.</param> /// <param name="range">The plot range to use.</param> /// <param name="layer">Graphics layer.</param> /// <param name="linePen">The pen to draw the line.</param> /// <param name="symbolGap">The size of the symbol gap. Argument is the original index of the data. The return value is the absolute symbol gap at this index. /// This function is null if no symbol gap is required.</param> /// <param name="skipFrequency">Skip frequency. Normally 1, thus all gaps are taken into account. If 2, only every 2nd gap is taken into account, and so on.</param> /// <param name="connectCircular">If true, there is a line connecting the start and the end of the range.</param> /// <param name="linePlotStyle">The line plot style.</param> public override void PaintOneRange( Graphics g, PointF[] allLinePoints, IPlotRange range, IPlotArea layer, PenX linePen, Func <int, double> symbolGap, int skipFrequency, bool connectCircular, LinePlotStyle linePlotStyle) { if (range.Length <= 1) { return; // seems to be only a single point, thus no connection possible } PointF[] stepPolylinePoints = GetStepPolylinePoints(allLinePoints, range, layer, connectCircular, out var numberOfPointsPerOriginalPoint, out var lastIdx); if (null != symbolGap) { foreach (var segmentRange in GetSegmentRanges(range, symbolGap, skipFrequency, connectCircular)) { if (segmentRange.IsFullRangeClosedCurve) // test if this is a closed polygon without any gaps -> draw a closed polygon and return { // use the whole circular arry to draw a closed polygon without any gaps g.DrawPolygon(linePen, stepPolylinePoints); } else { int plotIndexAtStart = segmentRange.IndexAtSubRangeStart * numberOfPointsPerOriginalPoint; int plotIndexAtEnd = segmentRange.IndexAtSubRangeEnd * numberOfPointsPerOriginalPoint; var shortenedPolyline = stepPolylinePoints.ShortenPartialPolylineByDistanceFromStartAndEnd(plotIndexAtStart, plotIndexAtEnd, segmentRange.GapAtSubRangeStart / 2, segmentRange.GapAtSubRangeEnd / 2); if (null != shortenedPolyline) { g.DrawLines(linePen, shortenedPolyline); } } } } else { if (connectCircular) { g.DrawPolygon(linePen, stepPolylinePoints); } else { g.DrawLines(linePen, stepPolylinePoints); } } }
void CopyFrom(ErrorBarPlotStyle from) { this._independentSymbolSize = from._independentSymbolSize; this._symbolSize = from._symbolSize; this._symbolGap = from._symbolGap; this._independentColor = from._independentColor; this._showEndBars = from._showEndBars; this._isHorizontalStyle = from._isHorizontalStyle; this._doNotShiftHorizontalPosition = from._doNotShiftHorizontalPosition; this._strokePen = (PenX)from._strokePen.Clone(); this._positiveErrorColumn = (NumericColumnProxy)from._positiveErrorColumn.Clone(); this._negativeErrorColumn = (NumericColumnProxy)from._negativeErrorColumn.Clone(); this._cachedLogicalShiftOfIndependent = from._cachedLogicalShiftOfIndependent; }
protected override System.Collections.Generic.IEnumerable <Main.DocumentNodeAndName> GetDocumentNodeChildrenWithName() { if (null != _cellPen) { yield return(new Main.DocumentNodeAndName(_cellPen, () => _cellPen = null, "CellPen")); } if (null != _textBrush) { yield return(new Main.DocumentNodeAndName(_textBrush, () => _textBrush = null, "TextBrush")); } if (null != _backgroundBrush) { yield return(new Main.DocumentNodeAndName(_backgroundBrush, () => _backgroundBrush = null, "BackgroundBrush")); } }
public ScatterPlotStyle(XYPlotScatterStyles.Shape shape, XYPlotScatterStyles.Style style, float size, float penWidth, Color penColor) { _shape = shape; _style = style; _dropLine = new CSPlaneIDList(); _pen = new PenX(penColor, penWidth); _symbolSize = size; _relativePenWidth = penWidth / size; _skipFreq = 1; // Cached values SetCachedValues(); CreateEventChain(); }
public LinePlotStyle(Altaxo.Main.Properties.IReadOnlyPropertyBag context) { var penWidth = GraphDocument.GetDefaultPenWidth(context); var color = GraphDocument.GetDefaultPlotColor(context); _linePen = new PenX(color, penWidth) { LineJoin = LineJoin.Bevel }; _ignoreMissingDataPoints = false; _connectionStyle = LineConnectionStyles.StraightConnection.Instance; _independentColor = false; CreateEventChain(); }
public DropLinePlotStyle(Altaxo.Main.Properties.IReadOnlyPropertyBag context) { _dropTargets = new CSPlaneIDList(new[] { new CSPlaneID(1, 0) }); var color = GraphDocument.GetDefaultPlotColor(context); double penWidth = GraphDocument.GetDefaultPenWidth(context); _pen = new PenX(color, penWidth) { ParentObject = this }; _lineWidth1Offset = penWidth; _lineWidth1Factor = 0; }
public ColumnStyle(ColumnStyle s) { _columnStyleType = s._columnStyleType; m_Size = s.m_Size; _isCellPenCustom = s._isCellPenCustom; m_CellPen = (PenX)s.m_CellPen.Clone(); m_TextFormat = (StringFormat)s.m_TextFormat.Clone(); m_TextFont = (Font)s.m_TextFont.Clone(); _isTextBrushCustom = s._isTextBrushCustom; m_TextBrush = (BrushX)s.m_TextBrush.Clone(); _isBackgroundBrushCustom = s._isBackgroundBrushCustom; m_BackgroundBrush = (BrushX)s.m_BackgroundBrush.Clone(); }
public BarGraphPlotStyle(BarGraphPlotStyle from) { this._relInnerGapWidth = from._relInnerGapWidth; this._relOuterGapWidth = from._relOuterGapWidth; this._width = from._width; this._position = from._position; this._independentColor = from._independentColor; this._fillBrush = from._fillBrush.Clone(); this._framePen = from._framePen == null ? null : (PenX)from._framePen.Clone(); this._startAtPreviousItem = from._startAtPreviousItem; this._previousItemYGap = from._previousItemYGap; this._usePhysicalBaseValue = from._usePhysicalBaseValue; this._baseValue = from._baseValue; this._parent = from._parent; }
internal LinePlotStyle(Altaxo.Serialization.Xml.IXmlDeserializationInfo info, bool oldDeserializationRequiresFullConstruction) { var penWidth = 1; var color = ColorSetManager.Instance.BuiltinDarkPlotColors[0]; _linePen = new PenX(color, penWidth) { LineJoin = LineJoin.Bevel }; _useSymbolGap = true; _ignoreMissingDataPoints = false; _connectionStyle = LineConnectionStyles.StraightConnection.Instance; _independentColor = false; CreateEventChain(); }
public ScatterPlotStyle() { this._shape = XYPlotScatterStyles.Shape.Square; this._style = XYPlotScatterStyles.Style.Solid; this._dropLine = new CSPlaneIDList(); this._pen = new PenX(Color.Black); this._independentColor = false; this._symbolSize = 8; this._relativePenWidth = 0.1f; this._skipFreq = 1; this._cachedFillPath = true; // since default is solid this._cachedFillBrush = new BrushX(Color.Black); this._cachedPath = GetPath(_shape, _style, _symbolSize); CreateEventChain(); }
public ColumnStyle(ColumnStyleType type) { _cellPen = new PenX(GdiColorHelper.ToNamedColor(SystemColors.InactiveBorder), 1) { ParentObject = this }; _textBrush = new BrushX(GdiColorHelper.ToNamedColor(SystemColors.WindowText)) { ParentObject = this }; _backgroundBrush = new BrushX(GdiColorHelper.ToNamedColor(SystemColors.Window)) { ParentObject = this }; _columnStyleType = type; SetDefaultCellBorder(); SetDefaultBackgroundBrush(); SetDefaultTextBrush(); SetDefaultTextFont(); }
public void ApplyGroupStyles(PlotGroupStyleCollection externalGroups, PlotGroupStyleCollection localGroups) { _cachedColorForIndexFunction = null; BarSizePosition2DGroupStyle bwp = PlotGroupStyle.GetStyleToApply <BarSizePosition2DGroupStyle>(externalGroups, localGroups); if (null != bwp) { bwp.Apply(out _relInnerGapX, out _relOuterGapX, out _xSizeLogical, out _xOffsetLogical); } if (!_independentFillColor) { if (null == _fillBrush) { _fillBrush = new BrushX(Drawing.ColorManagement.ColorSetManager.Instance.BuiltinDarkPlotColors[0]); } ColorGroupStyle.ApplyStyle(externalGroups, localGroups, delegate(NamedColor c) { _fillBrush.Color = c; }); // but if there is a color evaluation function, then use that function with higher priority VariableColorGroupStyle.ApplyStyle(externalGroups, localGroups, delegate(Func <int, Color> evalFunc) { _cachedColorForIndexFunction = evalFunc; }); } if (!_independentFrameColor) { if (null == _framePen) { _framePen = new PenX(Drawing.ColorManagement.ColorSetManager.Instance.BuiltinDarkPlotColors[0]); } ColorGroupStyle.ApplyStyle(externalGroups, localGroups, delegate(NamedColor c) { _framePen.Color = c; }); // but if there is a color evaluation function, then use that function with higher priority VariableColorGroupStyle.ApplyStyle(externalGroups, localGroups, delegate(Func <int, Color> evalFunc) { _cachedColorForIndexFunction = evalFunc; }); } }
public void CopyFrom(FillToCurvePlotStyle from, bool copyWithDataReferences, Main.EventFiring eventFiring) { if (object.ReferenceEquals(this, from)) { return; } using (var suspendToken = SuspendGetToken()) { _independentFillColor = from._independentFillColor; FillBrush = null == from._fillBrush ? null : from._fillBrush.Clone(); _independentFrameColor = from._independentFrameColor; _framePen = null == from._framePen ? null : from._framePen.Clone(); _fillToPrevPlotItem = from._fillToPrevPlotItem; _fillToNextPlotItem = from._fillToNextPlotItem; //this._parent = from._parent; suspendToken.Resume(eventFiring); } }
/// <summary> /// Copy operation. /// </summary> /// <param name="from">The AxisStyle to copy from</param> public void CopyFrom(AxisLineStyle from) { if (_axisPen != null) { WireEventChain(false); } this._axisPen = null == from._axisPen ? null : (PenX)from._axisPen.Clone(); this._axisPosition = from._axisPosition; this._showFirstDownMajorTicks = from._showFirstDownMajorTicks; this._showFirstDownMinorTicks = from._showFirstDownMinorTicks; this._showFirstUpMajorTicks = from._showFirstUpMajorTicks; this._showFirstUpMinorTicks = from._showFirstUpMinorTicks; this._majorTickLength = from._majorTickLength; this._majorTickPen = null == from._majorTickPen ? null : (PenX)from._majorTickPen; this._minorTickLength = from._minorTickLength; this._minorTickPen = (null == from._minorTickPen) ? null : (PenX)from._minorTickPen; this._cachedAxisStyleInfo = from._cachedAxisStyleInfo; this._parent = from._parent; // Rewire the event chain WireEventChain(true); }
public void CopyFrom(LinePlotStyle from, Main.EventFiring eventFiring) { if (object.ReferenceEquals(this, from)) return; using (var suspendToken = SuspendGetToken()) { this._independentSkipFrequency = from._independentSkipFrequency; this._skipFrequency = from._skipFrequency; this._ignoreMissingDataPoints = from._ignoreMissingDataPoints; this._independentOnShiftingGroupStyles = from._independentOnShiftingGroupStyles; this._connectCircular = from._connectCircular; this._connectionStyle = from._connectionStyle; this._linePen = null == from._linePen ? null : (PenX)from._linePen.Clone(); this._independentDashStyle = from._independentDashStyle; this._independentColor = from._independentColor; this._independentSymbolSize = from._independentSymbolSize; this._symbolSize = from._symbolSize; this._useSymbolGap = from._useSymbolGap; this._symbolGapOffset = from._symbolGapOffset; this._symbolGapFactor = from._symbolGapFactor; EhSelfChanged(); suspendToken.Resume(eventFiring); } }
public void CopyFrom(FillToCurvePlotStyle from, bool copyWithDataReferences, Main.EventFiring eventFiring) { if (object.ReferenceEquals(this, from)) return; using (var suspendToken = SuspendGetToken()) { this._independentFillColor = from._independentFillColor; this.FillBrush = null == from._fillBrush ? null : from._fillBrush.Clone(); this._independentFrameColor = from._independentFrameColor; this._framePen = null == from._framePen ? null : from._framePen.Clone(); this._fillToPrevPlotItem = from._fillToPrevPlotItem; this._fillToNextPlotItem = from._fillToNextPlotItem; //this._parent = from._parent; suspendToken.Resume(eventFiring); } }
/// <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); } } }
public ErrorBarPlotStyle() { this._strokePen = new PenX(Color.Black); }
/// <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(); } }
public DropLinePlotStyle(Altaxo.Main.Properties.IReadOnlyPropertyBag context) { this._dropTargets = new CSPlaneIDList(new[] { new CSPlaneID(1, 0) }); var color = GraphDocument.GetDefaultPlotColor(context); double penWidth = GraphDocument.GetDefaultPenWidth(context); _pen = new PenX(color, penWidth) { ParentObject = this }; _lineWidth1Offset = penWidth; _lineWidth1Factor = 0; }
public void CopyFrom(ScatterPlotStyle from, bool suppressChangeEvent) { this._shape = from._shape; this._style = from._style; if(null==this._dropLine) this._dropLine = new CSPlaneIDList(); else this._dropLine.Clear(); this._dropLine.AddClonedRange(from._dropLine); this._pen = null == from._pen ? null : (PenX)from._pen.Clone(); this._independentColor = from._independentColor; this._independentSymbolSize = from._independentSymbolSize; this._symbolSize = from._symbolSize; this._relativePenWidth = from._relativePenWidth; this._skipFreq = from._skipFreq; this._cachedPath = null == from._cachedPath ? null : (GraphicsPath)from._cachedPath.Clone(); this._cachedFillPath = from._cachedFillPath; this._cachedFillBrush = null == from._cachedFillBrush ? null : (BrushX)from._cachedFillBrush.Clone(); this._parent = from._parent; if (!suppressChangeEvent) OnChanged(); }
/// <summary> /// Template to make a line draw. /// </summary> /// <param name="g">Graphics context.</param> /// <param name="allLinePoints">The plot data. Don't use the Range property of the pdata, since it is overriden by the next argument.</param> /// <param name="range">The plot range to use.</param> /// <param name="layer">Graphics layer.</param> /// <param name="linePen">The pen to draw the line.</param> /// <param name="symbolGap">The size of the symbol gap. Argument is the original index of the data. The return value is the absolute symbol gap at this index. /// This function is null if no symbol gap is required.</param> /// <param name="skipFrequency">Skip frequency. Normally 1, thus all gaps are taken into account. If 2, only every 2nd gap is taken into account, and so on.</param> /// <param name="connectCircular">If true, there is a line connecting the start and the end of the range.</param> /// <param name="linePlotStyle">The line plot style.</param> public override void PaintOneRange( Graphics g, PointF[] allLinePoints, IPlotRange range, IPlotArea layer, PenX linePen, Func <int, double> symbolGap, int skipFrequency, bool connectCircular, LinePlotStyle linePlotStyle) { if (range.Length <= 1) { return; // seems to be only a single point, thus no connection possible } PointF[] circularLinePoints; int indexBasePlotPoints; // index of the first plot point of this range in circularLinePoints array if (connectCircular) // we have to copy the array in order to append the first point to the end { // otherwise, make a new array circularLinePoints = new PointF[range.Length + 1]; Array.Copy(allLinePoints, range.LowerBound, circularLinePoints, 0, range.Length); // Extract circularLinePoints[circularLinePoints.Length - 1] = circularLinePoints[0]; indexBasePlotPoints = 0; } else // use the array directly without copying { circularLinePoints = allLinePoints; indexBasePlotPoints = range.LowerBound; } if (null != symbolGap) { foreach (var segmentRange in GetSegmentRanges(range, symbolGap, skipFrequency, connectCircular)) { if (segmentRange.IsFullRangeClosedCurve) // test if this is a closed polygon without any gaps -> draw a closed polygon and return { // use the whole circular arry to draw a closed polygon without any gaps g.DrawPolygon(linePen, circularLinePoints); } else if (segmentRange.Length == 1) // special case only one line segment { int plotIndexAtStart = segmentRange.IndexAtSubRangeStart + indexBasePlotPoints; int plotIndexAtEnd = segmentRange.IndexAtSubRangeEnd + indexBasePlotPoints; var xdiff = circularLinePoints[plotIndexAtEnd].X - circularLinePoints[plotIndexAtStart].X; var ydiff = circularLinePoints[plotIndexAtEnd].Y - circularLinePoints[plotIndexAtStart].Y; var diffLength = System.Math.Sqrt(xdiff * xdiff + ydiff * ydiff); var relAtStart = (float)(0.5 * segmentRange.GapAtSubRangeStart / diffLength); // 0.5 because symbolGap is the full gap between two lines, thus between the symbol center and the beginning of the line it is only 1/2 var relAtEnd = (float)(0.5 * segmentRange.GapAtSubRangeEnd / diffLength); // 0.5 because symbolGap is the full gap between two lines, thus between the symbol center and the beginning of the line it is only 1/2 if ((relAtStart + relAtEnd) < 1) // a line only appears if sum of the gaps is smaller than 1 { var startx = circularLinePoints[plotIndexAtStart].X + relAtStart * xdiff; var starty = circularLinePoints[plotIndexAtStart].Y + relAtStart * ydiff; var stopx = circularLinePoints[plotIndexAtEnd].X - relAtEnd * xdiff; var stopy = circularLinePoints[plotIndexAtEnd].Y - relAtEnd * ydiff; g.DrawLine(linePen, startx, starty, stopx, stopy); } } else { int plotIndexAtStart = segmentRange.IndexAtSubRangeStart + indexBasePlotPoints; int plotIndexAtEnd = segmentRange.IndexAtSubRangeEnd + indexBasePlotPoints; var shortenedPolyline = circularLinePoints.ShortenPartialPolylineByDistanceFromStartAndEnd(plotIndexAtStart, plotIndexAtEnd, segmentRange.GapAtSubRangeStart / 2, segmentRange.GapAtSubRangeEnd / 2); if (null != shortenedPolyline) { g.DrawLines(linePen, shortenedPolyline); } } } // end for } else // no line symbol gap required, so we can use DrawLines or DrawPolygon to draw the lines { if (connectCircular) // array was already copied from original array { g.DrawPolygon(linePen, circularLinePoints); } else if (indexBasePlotPoints == 0 && range.Length == circularLinePoints.Length) // can use original array directly { g.DrawLines(linePen, circularLinePoints); } else { circularLinePoints = new PointF[range.Length]; Array.Copy(allLinePoints, range.LowerBound, circularLinePoints, 0, range.Length); g.DrawLines(linePen, circularLinePoints); } } }
private IEnumerable<Main.DocumentNodeAndName> GetMyDocumentNodeChildrenWithName() { if (null != _linePen) yield return new Main.DocumentNodeAndName(_linePen, () => _linePen = null, "LinePen"); if (null != _outlinePen) yield return new Main.DocumentNodeAndName(_outlinePen, () => _outlinePen = null, "OutlinePen"); }
protected override IEnumerable<Main.DocumentNodeAndName> GetDocumentNodeChildrenWithName() { if (null != _pen) yield return new DocumentNodeAndName(_pen, () => _pen = null, "Pen"); }
public ErrorBarPlotStyle(Altaxo.Main.Properties.IReadOnlyPropertyBag context) { var penWidth = GraphDocument.GetDefaultPenWidth(context); var color = GraphDocument.GetDefaultPlotColor(context); _lineWidth1Offset = penWidth; _lineWidth1Factor = 0; this._pen = new PenX(color, penWidth) { EndCap = new Altaxo.Graph.Gdi.LineCaps.SymBarLineCap(), ParentObject = this }; }
public DropLinePlotStyle(IEnumerable<CSPlaneID> planeIDs, PenX pen) { if (null == pen) throw new ArgumentNullException(nameof(pen)); ChildSetMember(ref _pen, pen); this._dropTargets = new CSPlaneIDList(planeIDs); // Cached values SetCachedValues(); }
public bool CopyFrom(object obj, bool copyWithDataReferences) { if (object.ReferenceEquals(this, obj)) return true; var from = obj as VectorCartesicPlotStyle; if (null != from) { this._meaningOfValues = from._meaningOfValues; this._independentSkipFrequency = from._independentSkipFrequency; this._skipFrequency = from._skipFrequency; this._ignoreMissingDataPoints = from._ignoreMissingDataPoints; this._useManualVectorLength = from._useManualVectorLength; this._vectorLengthOffset = from._vectorLengthOffset; this._vectorLengthFactor = from._vectorLengthFactor; this._independentSymbolSize = from._independentSymbolSize; this._symbolSize = from._symbolSize; this._strokePen = from._strokePen; this._independentColor = from._independentColor; _lineWidth1Offset = from._lineWidth1Offset; _lineWidth1Factor = from._lineWidth1Factor; this._endCapSizeFactor = from._endCapSizeFactor; this._endCapSizeOffset = from._endCapSizeOffset; this._useSymbolGap = from._useSymbolGap; this._symbolGapFactor = from._symbolGapFactor; this._symbolGapOffset = from._symbolGapOffset; this._independentSkipFrequency = from._independentSkipFrequency; this._skipFrequency = from._skipFrequency; this._independentOnShiftingGroupStyles = from._independentOnShiftingGroupStyles; this._cachedLogicalShiftX = from._cachedLogicalShiftX; this._cachedLogicalShiftY = from._cachedLogicalShiftY; if (copyWithDataReferences) { ChildCloneToMember(ref _columnX, from._columnX); ChildCloneToMember(ref _columnY, from._columnY); } EhSelfChanged(); return true; } return false; }
/// <summary> /// Copy operation. /// </summary> /// <param name="from">The AxisStyle to copy from</param> public void CopyFrom(AxisLineStyle from) { if (_axisPen != null) WireEventChain(false); this._axisPen = null == from._axisPen ? null : (PenX)from._axisPen.Clone(); this._axisPosition = from._axisPosition; this._showFirstDownMajorTicks = from._showFirstDownMajorTicks; this._showFirstDownMinorTicks = from._showFirstDownMinorTicks; this._showFirstUpMajorTicks = from._showFirstUpMajorTicks; this._showFirstUpMinorTicks = from._showFirstUpMinorTicks; this._majorTickLength = from._majorTickLength; this._majorTickPen = null==from._majorTickPen ? null : (PenX)from._majorTickPen; this._minorTickLength = from._minorTickLength; this._minorTickPen = (null==from._minorTickPen) ? null : (PenX)from._minorTickPen; this._cachedAxisStyleInfo = from._cachedAxisStyleInfo; this._parent = from._parent; // Rewire the event chain WireEventChain(true); }
/// <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(); } }
/// <summary> /// Template to make a line draw. /// </summary> /// <param name="g">Graphics context.</param> /// <param name="allLinePoints">The plot data. Don't use the Range property of the pdata, since it is overriden by the next argument.</param> /// <param name="range">The plot range to use.</param> /// <param name="layer">Graphics layer.</param> /// <param name="linePen">The pen to draw the line.</param> /// <param name="symbolGap">The size of the symbol gap. Argument is the original index of the data. The return value is the absolute symbol gap at this index. /// This function is null if no symbol gap is required.</param> /// <param name="skipFrequency">Skip frequency. Normally 1, thus all gaps are taken into account. If 2, only every 2nd gap is taken into account, and so on.</param> /// <param name="connectCircular">If true, there is a line connecting the start and the end of the range.</param> /// <param name="linePlotStyle">The line plot style.</param> public override void PaintOneRange( Graphics g, PointF[] allLinePoints, IPlotRange range, IPlotArea layer, PenX linePen, Func <int, double> symbolGap, int skipFrequency, bool connectCircular, LinePlotStyle linePlotStyle) { // Bezier is only supported with point numbers n=4+3*k // so trim the range appropriately if (range.Length < 4) { return; // then too less points are in this range } PointF[] circularLinePoints; if (connectCircular) { var circularLinePointsLengthM1 = 2 + TrimToValidBezierLength(range.Length); circularLinePoints = new PointF[circularLinePointsLengthM1 + 1]; Array.Copy(allLinePoints, range.LowerBound, circularLinePoints, 0, range.Length); // Extract circularLinePoints[circularLinePointsLengthM1] = circularLinePoints[0]; // amend missing control points if (circularLinePointsLengthM1 - range.Length >= 1) { circularLinePoints[circularLinePointsLengthM1 - 1] = GdiExtensionMethods.Interpolate(circularLinePoints[circularLinePointsLengthM1 - 3], circularLinePoints[circularLinePointsLengthM1], 0.5); // Last Control point should be halfway between } if (circularLinePointsLengthM1 - range.Length >= 2) { circularLinePoints[circularLinePointsLengthM1 - 2] = GdiExtensionMethods.Interpolate(circularLinePoints[circularLinePointsLengthM1 - 3], circularLinePoints[circularLinePointsLengthM1], 0.5); // Middle Control point should be halfway between previous fixed point and last(=first) fixed point } range = range.WithUpperBoundExtendedBy(circularLinePointsLengthM1 - range.Length); } else // not circular { var trimmedLength = TrimToValidBezierLength(range.Length); if (range.Length != trimmedLength) { range = range.WithUpperBoundShortenedBy(range.Length - trimmedLength); } if (range.LowerBound == 0 && trimmedLength == allLinePoints.Length) { circularLinePoints = allLinePoints; } else { circularLinePoints = new PointF[trimmedLength]; Array.Copy(allLinePoints, range.LowerBound, circularLinePoints, 0, trimmedLength); // Extract } } if (null != symbolGap) // circular with symbol gap { var realSkipFrequency = skipFrequency % 3 == 0 ? skipFrequency : skipFrequency * 3; // least common multiple of skipFrequency and 3 var skipLinePoints = new PointF[0]; foreach (var segmentRange in GetSegmentRanges(range, symbolGap, realSkipFrequency, connectCircular)) { if (segmentRange.IsFullRangeClosedCurve) // test if this is a closed polygon without any gaps -> draw a closed polygon and return { // use the whole circular arry to draw a closed polygon without any gaps g.DrawBeziers(linePen, circularLinePoints); } else { var skipLinePointsLength = 1 + segmentRange.Length; if (skipLinePoints.Length != skipLinePointsLength) { skipLinePoints = new PointF[skipLinePointsLength]; } Array.Copy(circularLinePoints, segmentRange.IndexAtSubRangeStart, skipLinePoints, 0, skipLinePointsLength); PointF[] shortenedLinePoints; if (segmentRange.GapAtSubRangeStart != 0 || segmentRange.GapAtSubRangeEnd != 0) { shortenedLinePoints = GdiExtensionMethods.ShortenBezierCurve(skipLinePoints, segmentRange.GapAtSubRangeStart / 2, segmentRange.GapAtSubRangeEnd / 2); } else { shortenedLinePoints = skipLinePoints; } if (null != shortenedLinePoints) { g.DrawBeziers(linePen, shortenedLinePoints); } } } } else // no symbol gap { g.DrawBeziers(linePen, circularLinePoints); } }
/// <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); } } }
/// <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); } } }