Answered by:
How to paint arc with path gradient using GDI+ (C#, WinForms)

Question
-
Here is the result I am trying to achieve:
Here is my attempt to create this using PathGradientBrush:
public partial class Form1 : Form { public Form1() { InitializeComponent(); } double outerRadius = 120; double innerRadius = 110; PointF DistanceFromCenter(PointF center, double radius, double angle) { double angleInRadians = angle * Math.PI / 180; return new PointF((float)(center.X + radius * (Math.Cos(angleInRadians))), (float)(center.Y + radius * (Math.Sin(angleInRadians)))); } protected override void OnPaint(PaintEventArgs e) { Graphics g = e.Graphics; GraphicsPath path = new GraphicsPath(); Point centerPoint = new Point(this.Width / 2, this.Width / 2); path.AddLine(this.DistanceFromCenter(centerPoint, innerRadius, 0), this.DistanceFromCenter(centerPoint, outerRadius, 0)); path.AddArc(new RectangleF(centerPoint.X - (float)outerRadius, centerPoint.Y - (float)outerRadius, (float)outerRadius * 2, (float)outerRadius * 2), 0, -180); path.AddLine(this.DistanceFromCenter(centerPoint, outerRadius, -180), this.DistanceFromCenter(centerPoint, innerRadius, -180)); path.AddArc(new RectangleF(centerPoint.X - (float)innerRadius, centerPoint.Y - (float)innerRadius, (float)innerRadius * 2, (float)innerRadius * 2), (float)0, -(float)180); PathGradientBrush pthGrBrush = new PathGradientBrush(path); // Set the color at the center of the path to red. pthGrBrush.CenterColor = Color.FromArgb(255, 255, 0, 0); // Set the colors of the points in the array. Color[] colors = { Color.FromArgb(255, 0, 0, 0), Color.FromArgb(255, 0, 255, 0), Color.FromArgb(255, 0, 0, 255), Color.FromArgb(255, 255, 255, 255), Color.FromArgb(255, 0, 0, 0), Color.FromArgb(255, 0, 255, 0), Color.FromArgb(255, 0, 0, 255), Color.FromArgb(255, 255, 255, 255), Color.FromArgb(255, 0, 0, 0), Color.FromArgb(255, 0, 255, 0)}; pthGrBrush.SurroundColors = colors; // Fill the path with the path gradient brush. g.FillPath(pthGrBrush, path); } }
Unfortunately, the result is not what I need:
Friday, August 22, 2014 5:55 AM
Answers
-
Hi,
the problem(s) are the pathPoints of the GraphicsPath, see:
bobpowell.net/pgb.aspx section Got them surrounded
You could surround the Arc by a harmonic polygon (around a fictitious circle) and so set points to the places where the colors should be:
[using System.Drawing.Drawing2D; needed]
public partial class Form1 : Form { PathGradientBrush _brush = null; private GraphicsPath _gPath = null; double outerRadius = 130; double innerRadius = 110; PointF centerPoint = new PointF(); public Form1() { InitializeComponent(); this.DoubleBuffered = true; centerPoint = new PointF(this.ClientSize.Width / 2f, this.ClientSize.Height / 2f); _gPath = GetPath(); RectangleF r = _gPath.GetBounds(); RectangleF r2 = new RectangleF(r.X, r.Y, r.Width, r.Height * 2); //pass colors for a full circle _brush = GetBrush(new Color[] { Color.Red, Color.Yellow, Color.Green, Color.Blue, Color.Red, Color.Yellow, Color.Green, Color.Blue, Color.Red }, r2, new PointF(this.ClientSize.Width / 2f, this.ClientSize.Height / 2f)); } PointF DistanceFromCenter(PointF center, double radius, double angle) { double angleInRadians = angle * Math.PI / 180; return new PointF((float)(center.X + radius * (Math.Cos(angleInRadians))), (float)(center.Y + radius * (Math.Sin(angleInRadians)))); } private GraphicsPath GetPath() { GraphicsPath fPath = new GraphicsPath(); fPath.AddLine(this.DistanceFromCenter(centerPoint, innerRadius, 0), this.DistanceFromCenter(centerPoint, outerRadius, 0)); fPath.AddArc(new RectangleF(centerPoint.X - (float)outerRadius, centerPoint.Y - (float)outerRadius, (float)outerRadius * 2, (float)outerRadius * 2), 0, -180); fPath.AddLine(this.DistanceFromCenter(centerPoint, outerRadius, -180), this.DistanceFromCenter(centerPoint, innerRadius, -180)); fPath.AddArc(new RectangleF(centerPoint.X - (float)innerRadius, centerPoint.Y - (float)innerRadius, (float)innerRadius * 2, (float)innerRadius * 2), (float)0, -(float)180); return fPath; } protected override void OnLayout(LayoutEventArgs levent) { base.OnLayout(levent); centerPoint = new PointF(this.ClientSize.Width / 2f, this.ClientSize.Height / 2f); if (_gPath != null) _gPath.Dispose(); _gPath = GetPath(); RectangleF r = _gPath.GetBounds(); RectangleF r2 = new RectangleF(r.X, r.Y, r.Width, r.Height * 2); if (_brush != null) _brush.Dispose(); _brush = GetBrush(new Color[] { Color.Red, Color.Yellow, Color.Green, Color.Blue, Color.Red, Color.Yellow, Color.Green, Color.Blue, Color.Red }, r2, new PointF(this.ClientSize.Width / 2f, this.ClientSize.Height / 2f)); this.Invalidate(); } protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); e.Graphics.SmoothingMode = SmoothingMode.AntiAlias; if (_brush != null) e.Graphics.FillPath(_brush, _gPath); } protected override void OnClosing(CancelEventArgs e) { if (_brush != null) _brush.Dispose(); if (_gPath != null) _gPath.Dispose(); base.OnClosing(e); } private PathGradientBrush GetBrush(Color[] Colors, RectangleF r, PointF centerOfBrush) { //based on a newsgroup post by Bob Powell //put a polygon to the GraphicsPath, so that there are PathPoints at the places where the colors should be int i = Colors.Length - 1; PointF[] points = new PointF[i + 1]; float a = 0f; int n = 0; float cx = r.Width / 2f; float cy = r.Height / 2f; //Faktorberechnung: //Winkel in gleichwinkligem Polygon: 180 * (n - 2) / n //Sin((180 * (n - 2) / n) / 2) * r = Höhe (Sinussatz) //r / Höhe = Faktor = 1 / Sin(Winkel) int w = (int)(Math.Floor((180.0 * (i - 2.0) / i) / 2.0)); double wi = w * Math.PI / 180.0; double faktor = 1.0 / Math.Sin(wi); float radx = (float)(cx * faktor); float rady = (float)(cy * faktor); while (a <= Math.PI * 2) { points[n] = new PointF((float)((cx + (Math.Cos(a) * radx))) + r.Left, (float)((cy + (Math.Sin(a) * rady))) + r.Top); n += 1; a += (float)(Math.PI * 2 / i); } points[i] = points[0]; GraphicsPath gPath = new GraphicsPath(); gPath.AddLines(points); PathGradientBrush fBrush = new PathGradientBrush(gPath); fBrush.CenterPoint = centerOfBrush; fBrush.CenterColor = Color.Transparent; fBrush.SurroundColors = new Color[] { Color.White }; try { fBrush.SurroundColors = Colors; } catch { MessageBox.Show("Zu viele Farben.", "Hinweis", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } return fBrush; } }
Regards,
Thorsten
- Edited by Thorsten Gudera Friday, August 22, 2014 10:58 PM
- Marked as answer by stefan stefanov Saturday, August 23, 2014 6:57 AM
Friday, August 22, 2014 10:56 PM
All replies
-
Hi,
the problem(s) are the pathPoints of the GraphicsPath, see:
bobpowell.net/pgb.aspx section Got them surrounded
You could surround the Arc by a harmonic polygon (around a fictitious circle) and so set points to the places where the colors should be:
[using System.Drawing.Drawing2D; needed]
public partial class Form1 : Form { PathGradientBrush _brush = null; private GraphicsPath _gPath = null; double outerRadius = 130; double innerRadius = 110; PointF centerPoint = new PointF(); public Form1() { InitializeComponent(); this.DoubleBuffered = true; centerPoint = new PointF(this.ClientSize.Width / 2f, this.ClientSize.Height / 2f); _gPath = GetPath(); RectangleF r = _gPath.GetBounds(); RectangleF r2 = new RectangleF(r.X, r.Y, r.Width, r.Height * 2); //pass colors for a full circle _brush = GetBrush(new Color[] { Color.Red, Color.Yellow, Color.Green, Color.Blue, Color.Red, Color.Yellow, Color.Green, Color.Blue, Color.Red }, r2, new PointF(this.ClientSize.Width / 2f, this.ClientSize.Height / 2f)); } PointF DistanceFromCenter(PointF center, double radius, double angle) { double angleInRadians = angle * Math.PI / 180; return new PointF((float)(center.X + radius * (Math.Cos(angleInRadians))), (float)(center.Y + radius * (Math.Sin(angleInRadians)))); } private GraphicsPath GetPath() { GraphicsPath fPath = new GraphicsPath(); fPath.AddLine(this.DistanceFromCenter(centerPoint, innerRadius, 0), this.DistanceFromCenter(centerPoint, outerRadius, 0)); fPath.AddArc(new RectangleF(centerPoint.X - (float)outerRadius, centerPoint.Y - (float)outerRadius, (float)outerRadius * 2, (float)outerRadius * 2), 0, -180); fPath.AddLine(this.DistanceFromCenter(centerPoint, outerRadius, -180), this.DistanceFromCenter(centerPoint, innerRadius, -180)); fPath.AddArc(new RectangleF(centerPoint.X - (float)innerRadius, centerPoint.Y - (float)innerRadius, (float)innerRadius * 2, (float)innerRadius * 2), (float)0, -(float)180); return fPath; } protected override void OnLayout(LayoutEventArgs levent) { base.OnLayout(levent); centerPoint = new PointF(this.ClientSize.Width / 2f, this.ClientSize.Height / 2f); if (_gPath != null) _gPath.Dispose(); _gPath = GetPath(); RectangleF r = _gPath.GetBounds(); RectangleF r2 = new RectangleF(r.X, r.Y, r.Width, r.Height * 2); if (_brush != null) _brush.Dispose(); _brush = GetBrush(new Color[] { Color.Red, Color.Yellow, Color.Green, Color.Blue, Color.Red, Color.Yellow, Color.Green, Color.Blue, Color.Red }, r2, new PointF(this.ClientSize.Width / 2f, this.ClientSize.Height / 2f)); this.Invalidate(); } protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); e.Graphics.SmoothingMode = SmoothingMode.AntiAlias; if (_brush != null) e.Graphics.FillPath(_brush, _gPath); } protected override void OnClosing(CancelEventArgs e) { if (_brush != null) _brush.Dispose(); if (_gPath != null) _gPath.Dispose(); base.OnClosing(e); } private PathGradientBrush GetBrush(Color[] Colors, RectangleF r, PointF centerOfBrush) { //based on a newsgroup post by Bob Powell //put a polygon to the GraphicsPath, so that there are PathPoints at the places where the colors should be int i = Colors.Length - 1; PointF[] points = new PointF[i + 1]; float a = 0f; int n = 0; float cx = r.Width / 2f; float cy = r.Height / 2f; //Faktorberechnung: //Winkel in gleichwinkligem Polygon: 180 * (n - 2) / n //Sin((180 * (n - 2) / n) / 2) * r = Höhe (Sinussatz) //r / Höhe = Faktor = 1 / Sin(Winkel) int w = (int)(Math.Floor((180.0 * (i - 2.0) / i) / 2.0)); double wi = w * Math.PI / 180.0; double faktor = 1.0 / Math.Sin(wi); float radx = (float)(cx * faktor); float rady = (float)(cy * faktor); while (a <= Math.PI * 2) { points[n] = new PointF((float)((cx + (Math.Cos(a) * radx))) + r.Left, (float)((cy + (Math.Sin(a) * rady))) + r.Top); n += 1; a += (float)(Math.PI * 2 / i); } points[i] = points[0]; GraphicsPath gPath = new GraphicsPath(); gPath.AddLines(points); PathGradientBrush fBrush = new PathGradientBrush(gPath); fBrush.CenterPoint = centerOfBrush; fBrush.CenterColor = Color.Transparent; fBrush.SurroundColors = new Color[] { Color.White }; try { fBrush.SurroundColors = Colors; } catch { MessageBox.Show("Zu viele Farben.", "Hinweis", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } return fBrush; } }
Regards,
Thorsten
- Edited by Thorsten Gudera Friday, August 22, 2014 10:58 PM
- Marked as answer by stefan stefanov Saturday, August 23, 2014 6:57 AM
Friday, August 22, 2014 10:56 PM -
Thank you!Saturday, August 23, 2014 6:58 AM