using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Drawing2D; namespace DevComponents.Instrumentation { internal class GaugeMarker : IDisposable { #region Private variables private List _Bitmaps; #endregion public GaugeMarker() { _Bitmaps = new List(); } #region Clear public void Clear() { foreach (BitmapEntry entry in _Bitmaps) entry.Bitmap.Dispose(); _Bitmaps.Clear(); } #endregion #region FindBitmap public Bitmap FindBitmap(GradientFillColor fillColor) { foreach (BitmapEntry entry in _Bitmaps) { if (entry.FillColor.IsEqualTo(fillColor) == true) return (entry.Bitmap); } return (null); } #endregion #region GetMarkerBitmap public Bitmap GetMarkerBitmap(Graphics g, GaugeMarkerStyle style, GradientFillColor fillColor, int width, int length) { Bitmap bitmap = FindBitmap(fillColor); if (bitmap == null) { width = Math.Max(width, 3); length = Math.Max(length, 3); bitmap = new Bitmap(width, length, g); _Bitmaps.Add(new BitmapEntry(fillColor, bitmap)); using (Graphics gBmp = Graphics.FromImage(bitmap)) { gBmp.SmoothingMode = SmoothingMode.AntiAlias; Rectangle r = new Rectangle(); r.Height = length; r.Width = width; using (GraphicsPath path = GetMarkerPath(style, r)) FillMarkerPath(gBmp, path, r, style, fillColor); } } return (bitmap); } #endregion #region FillMarkerPath internal void FillMarkerPath(Graphics g, GraphicsPath path, Rectangle r, GaugeMarkerStyle style, GradientFillColor fillColor) { GradientFillType fillType = GetMarkerFillType(style, fillColor); switch (fillType) { case GradientFillType.Angle: using (Brush br = fillColor.GetBrush(r)) { if (br is LinearGradientBrush) ((LinearGradientBrush)br).WrapMode = WrapMode.TileFlipXY; g.FillPath(br, path); } break; case GradientFillType.StartToEnd: using (Brush br = fillColor.GetBrush(r, 90)) { if (br is LinearGradientBrush) ((LinearGradientBrush)br).WrapMode = WrapMode.TileFlipXY; g.FillPath(br, path); } break; case GradientFillType.HorizontalCenter: r.Height /= 2; if (r.Height <= 0) r.Height = 1; using (LinearGradientBrush br = new LinearGradientBrush(r, fillColor.Start, fillColor.End, 90)) { br.WrapMode = WrapMode.TileFlipXY; g.FillPath(br, path); } break; case GradientFillType.VerticalCenter: r.Width /= 2; if (r.Width <= 0) r.Width = 1; using (LinearGradientBrush br = new LinearGradientBrush(r, fillColor.Start, fillColor.End, 0f)) { br.WrapMode = WrapMode.TileFlipXY; g.FillPath(br, path); } break; case GradientFillType.Center: using (PathGradientBrush br = new PathGradientBrush(path)) { br.CenterColor = fillColor.Start; br.SurroundColors = new Color[] { fillColor.End }; g.FillPath(br, path); } break; default: using (Brush br = new SolidBrush(fillColor.Start)) g.FillPath(br, path); break; } if (fillColor.BorderWidth > 0) { using (Pen pen = new Pen(fillColor.BorderColor, fillColor.BorderWidth)) { pen.Alignment = PenAlignment.Inset; g.DrawPath(pen, path); } } } #endregion #region GetMarkerFillType private GradientFillType GetMarkerFillType(GaugeMarkerStyle style, GradientFillColor fillColor) { if (fillColor.End.IsEmpty == true) return (GradientFillType.None); if (fillColor.GradientFillType == GradientFillType.Auto) { switch (style) { case GaugeMarkerStyle.Circle: case GaugeMarkerStyle.Star5: case GaugeMarkerStyle.Star7: return (GradientFillType.Center); default: return (GradientFillType.VerticalCenter); } } return (fillColor.GradientFillType); } #endregion #region GetMarkerPath internal GraphicsPath GetMarkerPath(GaugeMarkerStyle style, Rectangle r) { r.Inflate(-1, -1); if (r.Width > 0 && r.Height > 0) { switch (style) { case GaugeMarkerStyle.Circle: return (GetCirclePath(r)); case GaugeMarkerStyle.Diamond: return (GetDiamondPath(r)); case GaugeMarkerStyle.Hexagon: return (GetPolygonPath(r, 6, 90)); case GaugeMarkerStyle.Pentagon: return (GetPolygonPath(r, 5, 90)); case GaugeMarkerStyle.Rectangle: return (GetRectanglePath(r)); case GaugeMarkerStyle.Star5: return (GetStarPath(r, 5)); case GaugeMarkerStyle.Star7: return (GetStarPath(r, 7)); case GaugeMarkerStyle.Trapezoid: return (GetTrapezoidPath(r)); case GaugeMarkerStyle.Triangle: return (GetTrianglePath(r)); case GaugeMarkerStyle.Wedge: return (GetWedgePath(r)); default: return (GetRectanglePath(r)); } } return (null); } #region GetCirclePath private GraphicsPath GetCirclePath(Rectangle r) { GraphicsPath path = new GraphicsPath(); path.AddEllipse(r); return (path); } #endregion #region GetDiamondPath private GraphicsPath GetDiamondPath(Rectangle r) { GraphicsPath path = new GraphicsPath(); int dx = r.Width / 2; int dy = r.Height / 2; Point[] pts = { new Point(r.Left + dx, r.Top), new Point(r.Right, r.Top + dy), new Point(r.Left + dx, r.Bottom), new Point(r.Left, r.Top + dy), }; path.AddPolygon(pts); path.CloseAllFigures(); return (path); } #endregion #region GetPolygonPath private GraphicsPath GetPolygonPath(Rectangle r, int sides, float angle) { GraphicsPath path = new GraphicsPath(); double dx = (double)r.Width / 2; double radians = GetRadians(angle); double delta = GetRadians((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(); 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) { 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 = GetRadians(90); 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) { GraphicsPath path = new GraphicsPath(); int dx = r.Width / 2; Point[] pts = { new Point(r.Left, r.Top), new Point(r.Right, r.Top), new Point(r.Left + dx, r.Bottom), }; path.AddPolygon(pts); path.CloseAllFigures(); return (path); } #endregion #region GetTrapezoidPath private GraphicsPath GetTrapezoidPath(Rectangle r) { GraphicsPath path = new GraphicsPath(); int dx = (int)(r.Width * .28f); if (dx <= 0) dx = 1; Point[] pts = { new Point(r.Left, r.Top), new Point(r.Right, r.Top), new Point(r.Right - dx, r.Bottom), new Point(r.Left + dx, r.Bottom), }; path.AddPolygon(pts); path.CloseAllFigures(); return (path); } #endregion #region GetWedgePath private GraphicsPath GetWedgePath(Rectangle r) { GraphicsPath path = new GraphicsPath(); int dx = r.Width / 2; if ((r.Width % 2) == 1) dx++; if (dx <= 0) dx = 1; int dy = (int)Math.Sqrt((r.Width * r.Width) - (dx * dx)); int y = Math.Max(r.Y, r.Bottom - dy); Point[] pts = { new Point(r.X, r.Top), new Point(r.Right, r.Top), new Point(r.Right, y), new Point(r.X + dx, r.Bottom), new Point(r.X, y) }; path.AddPolygon(pts); path.CloseAllFigures(); return (path); } #endregion #endregion #region GetRadians /// /// Converts Degrees to Radians /// /// Degrees /// Radians internal double GetRadians(float theta) { return (theta * Math.PI / 180); } #endregion #region BitmapEntry private class BitmapEntry { public GradientFillColor FillColor; public Bitmap Bitmap; public BitmapEntry(GradientFillColor fillColor, Bitmap bitmap) { FillColor = (GradientFillColor)fillColor.Clone(); Bitmap = bitmap; } } #endregion #region IDisposable Members public void Dispose() { Clear(); } #endregion } #region Enums public enum GaugeMarkerStyle { Circle, Diamond, Hexagon, Pentagon, Rectangle, Star5, Star7, Trapezoid, Triangle, Wedge, None } #endregion }