566 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			566 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
using System;
 | 
						|
using System.Collections.Generic;
 | 
						|
using System.Drawing;
 | 
						|
using System.Drawing.Drawing2D;
 | 
						|
using System.Text;
 | 
						|
using DevComponents.DotNetBar.Charts.Style;
 | 
						|
 | 
						|
namespace DevComponents.DotNetBar.Charts
 | 
						|
{
 | 
						|
    internal class PointMarker : IDisposable
 | 
						|
    {
 | 
						|
        #region Private variables
 | 
						|
 | 
						|
        private List<BitmapEntry> _Bitmaps = new List<BitmapEntry>();
 | 
						|
 | 
						|
        #endregion
 | 
						|
 | 
						|
        #region GetMarkerBitmap
 | 
						|
 | 
						|
        public Bitmap GetMarkerBitmap(Graphics g, PointMarkerType markerType, int markerPoints, 
 | 
						|
            Size size, int markerRotation, Background background, Color borderColor, int borderWidth)
 | 
						|
        {
 | 
						|
            if (markerType == PointMarkerType.None || markerType == PointMarkerType.NotSet)
 | 
						|
                return (null);
 | 
						|
 | 
						|
            if (markerType == PointMarkerType.Cross ||
 | 
						|
                background == null || background.IsEmpty)
 | 
						|
            {
 | 
						|
                if (borderColor.IsEmpty)
 | 
						|
                    borderColor = Color.Black;
 | 
						|
            }
 | 
						|
 | 
						|
            // Add margin to permit better antialiasing of image
 | 
						|
 | 
						|
            size.Width++;
 | 
						|
            size.Height++;
 | 
						|
 | 
						|
            Bitmap bitmap = null;
 | 
						|
 | 
						|
            bitmap = FindBitmap(markerType, markerPoints,
 | 
						|
                size, markerRotation, background, borderColor, borderWidth);
 | 
						|
 | 
						|
            if (bitmap == null)
 | 
						|
            {
 | 
						|
                size.Width = Math.Max(size.Width, 3);
 | 
						|
                size.Height = Math.Max(size.Height, 3);
 | 
						|
 | 
						|
                Rectangle r = new Rectangle(Point.Empty, size);
 | 
						|
 | 
						|
                using (GraphicsPath path =
 | 
						|
                    GetMarkerPath(markerType, markerPoints, markerRotation, r, borderWidth))
 | 
						|
                {
 | 
						|
                    if (path != null)
 | 
						|
                    {
 | 
						|
                        bitmap = new Bitmap(size.Width, size.Height, g);
 | 
						|
 | 
						|
                        using (Graphics gBmp = Graphics.FromImage(bitmap))
 | 
						|
                        {
 | 
						|
                            gBmp.SmoothingMode = SmoothingMode.AntiAlias;
 | 
						|
 | 
						|
                            FillMarkerPath(gBmp, path, r, markerType, background, borderColor, borderWidth);
 | 
						|
 | 
						|
                            if (markerRotation != 0 && markerRotation != -1)
 | 
						|
                            {
 | 
						|
                                Bitmap bitmap2 = RotatePic(bitmap, markerRotation);
 | 
						|
 | 
						|
                                bitmap.Dispose();
 | 
						|
 | 
						|
                                bitmap = bitmap2;
 | 
						|
                            }
 | 
						|
 | 
						|
                            _Bitmaps.Add(new BitmapEntry(markerType, size, markerPoints,
 | 
						|
                                markerRotation, background, borderColor, borderWidth, bitmap));
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            return (bitmap);
 | 
						|
        }
 | 
						|
 | 
						|
        #endregion
 | 
						|
 | 
						|
        #region FindBitmap
 | 
						|
 | 
						|
        public Bitmap FindBitmap(PointMarkerType markerType, int markerPoints,
 | 
						|
            Size size, int markerRotation, Background background, Color borderColor, int borderWidth)
 | 
						|
        {
 | 
						|
            foreach (BitmapEntry entry in _Bitmaps)
 | 
						|
            {
 | 
						|
                if (entry.MarkerType == markerType &&
 | 
						|
                    entry.MarkerPoints == markerPoints &&
 | 
						|
                    entry.MarkerRotation == markerRotation &&
 | 
						|
                    entry.MarkerSize.Equals(size) &&
 | 
						|
                    entry.BorderWidth == borderWidth &&
 | 
						|
                    entry.BorderColor.Equals(borderColor) &&
 | 
						|
                    entry.Background.IsEqualTo(background))
 | 
						|
                {
 | 
						|
                    return (entry.Bitmap);
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            return (null);
 | 
						|
        }
 | 
						|
 | 
						|
        #endregion
 | 
						|
 | 
						|
        #region GetMarkerPath
 | 
						|
 | 
						|
        internal GraphicsPath GetMarkerPath( PointMarkerType markerType,
 | 
						|
            int markerPoints, int markerRotation, Rectangle r, int borderWidth)
 | 
						|
        {
 | 
						|
            r.Inflate(-borderWidth, -borderWidth);
 | 
						|
 | 
						|
            if (r.Width > 0 && r.Height > 0)
 | 
						|
            {
 | 
						|
                switch (markerType)
 | 
						|
                {
 | 
						|
                    case PointMarkerType.Ellipse:
 | 
						|
                        return (GetCirclePath(r));
 | 
						|
 | 
						|
                    case PointMarkerType.Cross:
 | 
						|
                        return (GetCrossPath(r, markerPoints));
 | 
						|
 | 
						|
                    case PointMarkerType.Diamond:
 | 
						|
                        return (GetDiamondPath(r));
 | 
						|
 | 
						|
                    case PointMarkerType.Rectangle:
 | 
						|
                        return (GetRectanglePath(r));
 | 
						|
 | 
						|
                    case PointMarkerType.Star:
 | 
						|
                        return (GetStarPath(r, markerPoints));
 | 
						|
 | 
						|
                    case PointMarkerType.Triangle:
 | 
						|
                        return (GetTrianglePath(r));
 | 
						|
 | 
						|
                    default:
 | 
						|
                        return (GetPolygonPath(r, markerPoints));
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            return (null);
 | 
						|
        }
 | 
						|
 | 
						|
        #region GetCirclePath
 | 
						|
 | 
						|
        private GraphicsPath GetCirclePath(Rectangle r)
 | 
						|
        {
 | 
						|
            GraphicsPath path = new GraphicsPath();
 | 
						|
 | 
						|
            path.AddEllipse(r);
 | 
						|
 | 
						|
            return (path);
 | 
						|
        }
 | 
						|
 | 
						|
        #endregion
 | 
						|
 | 
						|
        #region GetCrossPath
 | 
						|
 | 
						|
        private GraphicsPath GetCrossPath(Rectangle r, int points)
 | 
						|
        {
 | 
						|
            GraphicsPath path = new GraphicsPath();
 | 
						|
 | 
						|
            PointF[] pts = new PointF[2 * points];
 | 
						|
 | 
						|
            double rx1 = r.Width / 2;
 | 
						|
            double ry1 = r.Height / 2;
 | 
						|
 | 
						|
            if (rx1 < 2)
 | 
						|
                rx1 = 2;
 | 
						|
 | 
						|
            if (ry1 < 2)
 | 
						|
                ry1 = 2;
 | 
						|
 | 
						|
            double cx = r.X + rx1;
 | 
						|
            double cy = r.Y + ry1;
 | 
						|
 | 
						|
            double theta = MathHelper.ToRadians(270);
 | 
						|
            double dtheta = Math.PI / points;
 | 
						|
 | 
						|
            for (int i = 0; i < 2 * points; i += 2)
 | 
						|
            {
 | 
						|
                pts[i] = new PointF(
 | 
						|
                    (float)(cx + rx1 * Math.Cos(theta)),
 | 
						|
                    (float)(cy + ry1 * Math.Sin(theta)));
 | 
						|
 | 
						|
                pts[i + 1] = new PointF((float)cx, (float)cy);
 | 
						|
 | 
						|
                theta += (dtheta * 2);
 | 
						|
            }
 | 
						|
 | 
						|
            path.AddPolygon(pts);
 | 
						|
 | 
						|
            path.CloseAllFigures();
 | 
						|
 | 
						|
            return (path);
 | 
						|
        }
 | 
						|
 | 
						|
        #endregion
 | 
						|
 | 
						|
        #region GetDiamondPath
 | 
						|
 | 
						|
        private GraphicsPath GetDiamondPath(Rectangle r)
 | 
						|
        {
 | 
						|
            GraphicsPath path = new GraphicsPath();
 | 
						|
 | 
						|
            int dx = r.Width / 2;
 | 
						|
            int dy = r.Height / 2;
 | 
						|
 | 
						|
            int mx = r.X + dx;
 | 
						|
            int my = r.Y + dy;
 | 
						|
 | 
						|
            Point[] pts =
 | 
						|
            {
 | 
						|
                new Point(mx, my - dy), 
 | 
						|
                new Point(mx + dx, my),
 | 
						|
                new Point(mx, my + dy),
 | 
						|
                new Point(mx - dx, my),
 | 
						|
            };
 | 
						|
 | 
						|
            path.AddPolygon(pts);
 | 
						|
 | 
						|
            path.CloseAllFigures();
 | 
						|
 | 
						|
            return (path);
 | 
						|
        }
 | 
						|
 | 
						|
        #endregion
 | 
						|
 | 
						|
        #region GetPolygonPath
 | 
						|
 | 
						|
        private GraphicsPath GetPolygonPath(Rectangle r, int sides)
 | 
						|
        {
 | 
						|
            if (sides <= 4)
 | 
						|
                return (GetRectanglePath(r));
 | 
						|
 | 
						|
            GraphicsPath path = new GraphicsPath();
 | 
						|
 | 
						|
            int radius = Math.Min(r.Width, r.Height);
 | 
						|
 | 
						|
            float dx = (float)radius / 2;
 | 
						|
            float radians = (float)MathHelper.ToRadians(270);
 | 
						|
            float delta = (float)MathHelper.ToRadians((float)360 / sides);
 | 
						|
 | 
						|
            Point[] pts = new Point[sides];
 | 
						|
 | 
						|
            for (int i = 0; i < sides; i++)
 | 
						|
            {
 | 
						|
                pts[i] = new Point(
 | 
						|
                    (int)(dx * Math.Cos(radians) + dx + r.X),
 | 
						|
                    (int)(dx * Math.Sin(radians) + dx + r.Y));
 | 
						|
 | 
						|
                radians += delta;
 | 
						|
            }
 | 
						|
 | 
						|
            path.AddPolygon(pts);
 | 
						|
 | 
						|
            path.CloseAllFigures();
 | 
						|
 | 
						|
            if (r.Width != r.Height)
 | 
						|
            {
 | 
						|
                PointF[] dp = 
 | 
						|
                { 
 | 
						|
                    new PointF(0, 0), 
 | 
						|
                    new PointF(r.Width, 0), 
 | 
						|
                    new PointF(0, r.Height),
 | 
						|
                };
 | 
						|
 | 
						|
                path.Warp(dp, new RectangleF(0, 0, radius, radius));
 | 
						|
            }
 | 
						|
 | 
						|
            return (path);
 | 
						|
        }
 | 
						|
 | 
						|
        #endregion
 | 
						|
 | 
						|
        #region GetRectanglePath
 | 
						|
 | 
						|
        private GraphicsPath GetRectanglePath(Rectangle r)
 | 
						|
        {
 | 
						|
            GraphicsPath path = new GraphicsPath();
 | 
						|
 | 
						|
            path.AddRectangle(r);
 | 
						|
 | 
						|
            return (path);
 | 
						|
        }
 | 
						|
        
 | 
						|
        #endregion
 | 
						|
 | 
						|
        #region GetStarPath
 | 
						|
 | 
						|
        private GraphicsPath GetStarPath(Rectangle r, int points)
 | 
						|
        {
 | 
						|
            if (points < 2)
 | 
						|
                points = 2;
 | 
						|
 | 
						|
            GraphicsPath path = new GraphicsPath();
 | 
						|
 | 
						|
            PointF[] pts = new PointF[2 * points];
 | 
						|
 | 
						|
            double rx1 = r.Width / 2;
 | 
						|
            double ry1 = r.Height / 2;
 | 
						|
 | 
						|
            if (rx1 < 2)
 | 
						|
                rx1 = 2;
 | 
						|
 | 
						|
            if (ry1 < 2)
 | 
						|
                ry1 = 2;
 | 
						|
 | 
						|
            double rx2 = rx1 / 2;
 | 
						|
            double ry2 = ry1 / 2;
 | 
						|
 | 
						|
            double cx = r.X + rx1;
 | 
						|
            double cy = r.Y + ry1;
 | 
						|
 | 
						|
            double theta = MathHelper.ToRadians(270);
 | 
						|
            double dtheta = Math.PI / points;
 | 
						|
 | 
						|
            for (int i = 0; i < 2 * points; i += 2)
 | 
						|
            {
 | 
						|
                pts[i] = new PointF(
 | 
						|
                    (float)(cx + rx1 * Math.Cos(theta)),
 | 
						|
                    (float)(cy + ry1 * Math.Sin(theta)));
 | 
						|
 | 
						|
                theta += dtheta;
 | 
						|
 | 
						|
                pts[i + 1] = new PointF(
 | 
						|
                    (float)(cx + rx2 * Math.Cos(theta)),
 | 
						|
                    (float)(cy + ry2 * Math.Sin(theta)));
 | 
						|
 | 
						|
                theta += dtheta;
 | 
						|
            }
 | 
						|
 | 
						|
            path.AddPolygon(pts);
 | 
						|
 | 
						|
            path.CloseAllFigures();
 | 
						|
 | 
						|
            return (path);
 | 
						|
        }
 | 
						|
 | 
						|
        #endregion
 | 
						|
 | 
						|
        #region GetTrianglePath
 | 
						|
 | 
						|
        private GraphicsPath GetTrianglePath(Rectangle r)
 | 
						|
        {
 | 
						|
            // Equal height and width will not be adjusted to make
 | 
						|
            // an equalaterial triangle - thus rotation will skew image.
 | 
						|
 | 
						|
            GraphicsPath path = new GraphicsPath();
 | 
						|
 | 
						|
            int dx = r.Width / 2;
 | 
						|
            int dy = r.Height / 2;
 | 
						|
 | 
						|
            Point[] pts = {
 | 
						|
                new Point(r.X + dx, r.Y), 
 | 
						|
                new Point(r.X , r.Y + dy * 2),
 | 
						|
                new Point(r.X + dx * 2, r.Y + dy * 2),
 | 
						|
            };
 | 
						|
 | 
						|
            path.AddPolygon(pts);
 | 
						|
 | 
						|
            path.CloseAllFigures();
 | 
						|
 | 
						|
            return (path);
 | 
						|
        }
 | 
						|
 | 
						|
        #endregion
 | 
						|
 | 
						|
        #endregion
 | 
						|
 | 
						|
        #region FillMarkerPath
 | 
						|
 | 
						|
        internal void FillMarkerPath(Graphics g, GraphicsPath path, Rectangle r, 
 | 
						|
            PointMarkerType markerType, Background background, Color borderColor, int borderWidth)
 | 
						|
        {
 | 
						|
            if (markerType != PointMarkerType.Cross)
 | 
						|
            {
 | 
						|
                BackFillType fillType = GetMarkerFillType(markerType, background);
 | 
						|
 | 
						|
                using (Brush br = background.GetBrush(r, -1, fillType))
 | 
						|
                    g.FillPath(br, path);
 | 
						|
            }
 | 
						|
 | 
						|
            if (borderColor.IsEmpty == false && borderWidth > 0)
 | 
						|
            {
 | 
						|
                using (Pen pen = new Pen(borderColor, borderWidth))
 | 
						|
                    g.DrawPath(pen, path);
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        #region GetMarkerFillType
 | 
						|
 | 
						|
        private BackFillType GetMarkerFillType(PointMarkerType markerType, Background background)
 | 
						|
        {
 | 
						|
            if (background.Color2.IsEmpty == true)
 | 
						|
                return (BackFillType.None);
 | 
						|
 | 
						|
            if (background.BackFillType == BackFillType.Auto)
 | 
						|
            {
 | 
						|
                switch (markerType)
 | 
						|
                {
 | 
						|
                    case PointMarkerType.Ellipse:
 | 
						|
                    case PointMarkerType.Star:
 | 
						|
                        return (BackFillType.Center);
 | 
						|
 | 
						|
                    default:
 | 
						|
                        return (BackFillType.VerticalCenter);
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            return (background.BackFillType);
 | 
						|
        }
 | 
						|
 | 
						|
        #endregion
 | 
						|
 | 
						|
        #endregion
 | 
						|
 | 
						|
        #region RotatePic
 | 
						|
 | 
						|
        private Bitmap RotatePic(Bitmap obmp, float angle)
 | 
						|
        {
 | 
						|
            float rad = (float)MathHelper.ToRadians(angle);
 | 
						|
 | 
						|
            double fW = Math.Abs((Math.Cos(rad) * obmp.Width)) + Math.Abs((Math.Sin(rad) * obmp.Height));
 | 
						|
            double fH = Math.Abs((Math.Sin(rad) * obmp.Width)) + Math.Abs((Math.Cos(rad) * obmp.Height));
 | 
						|
 | 
						|
            Bitmap nbmp = new Bitmap((int)Math.Ceiling(fW), (int)Math.Ceiling(fH));
 | 
						|
 | 
						|
            using (Graphics g = Graphics.FromImage(nbmp))
 | 
						|
            {
 | 
						|
                g.SmoothingMode = SmoothingMode.AntiAlias;
 | 
						|
                g.InterpolationMode = InterpolationMode.HighQualityBicubic;
 | 
						|
 | 
						|
                float hw = nbmp.Width / 2f;
 | 
						|
                float hh = nbmp.Height / 2f;
 | 
						|
 | 
						|
                Matrix m = g.Transform;
 | 
						|
 | 
						|
                m.RotateAt(angle, new PointF(hw, hh), MatrixOrder.Append);
 | 
						|
 | 
						|
                g.Transform = m;
 | 
						|
 | 
						|
                g.DrawImage(obmp, new PointF((float)((nbmp.Width - obmp.Width) / 2), (float)((nbmp.Height - obmp.Height) / 2)));
 | 
						|
            }
 | 
						|
 | 
						|
            return nbmp;
 | 
						|
        }
 | 
						|
 | 
						|
        #endregion
 | 
						|
 | 
						|
        #region Clear
 | 
						|
 | 
						|
        public void Clear()
 | 
						|
        {
 | 
						|
            foreach (BitmapEntry entry in _Bitmaps)
 | 
						|
            {
 | 
						|
                entry.Background.Dispose();
 | 
						|
                entry.Bitmap.Dispose();
 | 
						|
            }
 | 
						|
 | 
						|
            _Bitmaps.Clear();
 | 
						|
        }
 | 
						|
 | 
						|
        #endregion
 | 
						|
 | 
						|
        #region IDisposable Members
 | 
						|
 | 
						|
        public void Dispose()
 | 
						|
        {
 | 
						|
            Clear();
 | 
						|
        }
 | 
						|
 | 
						|
        #endregion
 | 
						|
 | 
						|
        #region BitmapEntry
 | 
						|
 | 
						|
        private class BitmapEntry
 | 
						|
        {
 | 
						|
            public PointMarkerType MarkerType;
 | 
						|
            public Size MarkerSize;
 | 
						|
            public int MarkerPoints;
 | 
						|
            public int MarkerRotation;
 | 
						|
 | 
						|
            public Background Background;
 | 
						|
            public Color BorderColor;
 | 
						|
            public int BorderWidth;
 | 
						|
 | 
						|
            public Bitmap Bitmap;
 | 
						|
 | 
						|
            public BitmapEntry(PointMarkerType markerType, Size markerSize, int markerPoints,
 | 
						|
                int markerRotation, Background background, Color borderColor, int borderWidth, Bitmap bitmap)
 | 
						|
            {
 | 
						|
                MarkerType = markerType;
 | 
						|
                MarkerSize = markerSize;
 | 
						|
                MarkerPoints = markerPoints;
 | 
						|
                MarkerRotation = markerRotation;
 | 
						|
 | 
						|
                Background = background.Copy();
 | 
						|
                BorderColor = borderColor;
 | 
						|
                BorderWidth = borderWidth;
 | 
						|
 | 
						|
                Bitmap = bitmap;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        #endregion
 | 
						|
    }
 | 
						|
 | 
						|
    #region enums
 | 
						|
 | 
						|
    #region PointMarkerType
 | 
						|
 | 
						|
    public enum PointMarkerType
 | 
						|
    {
 | 
						|
        /// <summary>
 | 
						|
        /// Type not set.
 | 
						|
        /// </summary>
 | 
						|
        NotSet = -1,
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// No Marker
 | 
						|
        /// </summary>
 | 
						|
        None,
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// Cross
 | 
						|
        /// </summary>
 | 
						|
        Cross,
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// Diamond
 | 
						|
        /// </summary>
 | 
						|
        Diamond,
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// Ellipse
 | 
						|
        /// </summary>
 | 
						|
        Ellipse,
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// Polygon (Pentagon, Hexagon, etc)
 | 
						|
        /// </summary>
 | 
						|
        Polygon,
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// Rectangle
 | 
						|
        /// </summary>
 | 
						|
        Rectangle,
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// Star
 | 
						|
        /// </summary>
 | 
						|
        Star,
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// Triangle
 | 
						|
        /// </summary>
 | 
						|
        Triangle,
 | 
						|
    }
 | 
						|
 | 
						|
    #endregion
 | 
						|
 | 
						|
    #endregion
 | 
						|
}
 |