using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Drawing2D; using System.Linq; using Steema.TeeChart.Drawing; namespace DelftTools.Controls.Swf.Charting.Series { /// /// TeeChart wrapper class to fix PolygonSeries when drawn into a 2D axes (was meant for drawing on a Map). /// internal class PolygonSeries : Steema.TeeChart.Styles.PolygonSeries { private bool autoClose; /// /// Closes the polygon automatically when true. /// public bool AutoClose { get { return autoClose; } set { autoClose = value; Repaint(); } } /// /// Override Draw method and use the TeeChart Graphics3D object to draw the polygon shape /// public override void Draw() { if (XValues.Count < 2) { return; } if (XValues.Count != YValues.Count) { // Just to be sure. I think TeeChart already accounts for this in Add methods. throw new Exception("Number of X values should be equal to the number of Y values"); } var g = Chart.Graphics3D; PrepareGraphics3D(g); g.ClipRectangle(Chart.ChartBounds); // Draw polygon groups: foreach (var pointList in GetDrawingPoints()) { g.Polygon(pointList); } g.UnClip(); } /// /// Override DrawLegendShape because it includes a call to Polygon().ParentShape.... which is null if we do not use Polygon to create it. /// /// /// /// protected override void DrawLegendShape(Graphics3D g, int valueIndex, Rectangle rect) { PrepareGraphics3D(g); var oldWidth = 1; if (g.Pen.Visible) { oldWidth = g.Pen.Width; g.Pen.Width = 1; } base.DrawLegendShape(g, valueIndex, rect); if (g.Pen.Visible) { g.Pen.Width = oldWidth; } } /// /// Override SetActive because it includes a call to Polygon().ParentShape.... which is null if we do not use Polygon to create it. /// /// protected override void SetActive(bool value) { SetBooleanProperty(ref bActive, value); } /// /// Override PrepareLegendCanvas because it includes a call to Polygon().ParentShape.... which is null if we do not use Polygon to create it. /// /// /// /// /// protected override void PrepareLegendCanvas(Graphics3D g, int valueIndex, ref Color backColor, ref ChartBrush aBrush) {} private void PrepareGraphics3D(Graphics3D g) { g.Pen = Pen; g.Brush = bBrush; g.Pen.DrawingPen.LineJoin = LineJoin.Round; } private IEnumerable GetDrawingPoints() { var pointGroupsToRender = new List(); var currentPointsGroup = new List(); for (int i = 0; i < XValues.Count; i++) { var xValue = XValues[i]; var yValue = YValues[i]; if (double.IsNaN(xValue) || double.IsNaN(yValue)) { continue; } // TODO: How to distinguish null?? // Can cause collision when a regular value has the same value! if (xValue == DefaultNullValue || yValue == DefaultNullValue) { AddToPointsList(pointGroupsToRender, currentPointsGroup); continue; } currentPointsGroup.Add(new Point(CalcXPosValue(xValue), CalcYPosValue(yValue))); } AddToPointsList(pointGroupsToRender, currentPointsGroup); return pointGroupsToRender; } private void AddToPointsList(ICollection pointGroupsToRender, List currentPointsGroup) { if (!currentPointsGroup.Any()) { return; // Do nothing for empty list } if (autoClose && (currentPointsGroup[0].X != currentPointsGroup.Last().X || currentPointsGroup[0].Y != currentPointsGroup.Last().Y)) { currentPointsGroup.Add(currentPointsGroup[0]); } pointGroupsToRender.Add(currentPointsGroup.ToArray()); currentPointsGroup.Clear(); } } }