问题
Is it possible to fill a N-gon, for example a 4 point polygon, that has a different color at each point and have GDI+ to do the color blending? I am looking for something like this:
but for 4 point shapes.
回答1:
After playing around with Hans' idea of using a path filling, I think this will actually be the best way to solve this.
However neither a GraphicsPath
nor Clipping
nor the bounding rectangle are used. Instead we use a special overload that takes a point array; those points are matched with the SurroundColors
property of a PathGradientBrush
; this way the colors don't change radially as usually but stay pinned to the corner points..
Here are six examples:
The Color list is not exactly taken from a spectrum:
List<Color> colors = new List<Color>()
{ Color.Blue, Color.Lime, Color.Red, Color.Magenta , Color.MediumOrchid,
Color.MediumSeaGreen, Color.LightSeaGreen, Color.LightSteelBlue, Color.DarkCyan};
and I use a simple structure to hold a Point
and a Color
:
struct cPoint
{
public Point pt;
public Color col;
public cPoint(int x, int y, Color c)
{ pt = new Point(x,y); col = c;}
}
My form has a PictureBox
and a NumericUpDown
. The NuD calls the pictureBox.Paint
:
private void numericUpDown1_ValueChanged(object sender, EventArgs e)
{
pictureBox1.Invalidate();
}
..which calls two functions:
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
points = getPolyList(colors.Take( (int) numericUpDown1.Value).ToList(),
pictureBox2.ClientSize);
DrawPolyGradient(e.Graphics, points, pictureBox2.ClientRectangle);
}
The list of cPoints
is created with simple trigonometry, which works fine for regular polygons:
List<cPoint> getPolyList(List<Color> colors, Size size)
{
int number = colors.Count;
List<cPoint> cPoints = new List<cPoint>();
int x2 = size.Width / 2;
int y2 = size.Height / 2;
for (int i = 0; i < number; i++)
{
double a = Math.PI / 180f * (i * 360d / number - 90);
int x = x2 + (int)( Math.Cos(a) * (x2 - 15)); // don't overdraw
int y = y2 + (int)( Math.Sin(a) * (x2 - 15)); // don't overdraw
cPoints.Add(new cPoint(x, y, colors[i]));
}
return cPoints;
}
The drawing code is in a function of its own:
void DrawPolyGradient(Graphics G, List<cPoint> cPoints, Rectangle bounds)
{
int r = 0; int g = 0; int b = 0; int c = cPoints.Count;
foreach (Color col in cPoints.Select(x => x.col))
{ r += col.R; g += col.G; b += col.B; }
Color centercolor = Color.FromArgb(r / c, r / c, r / c);
PathGradientBrush brush = new PathGradientBrush(cPoints.Select(x => x.pt).ToArray());
brush.CenterPoint = new PointF(bounds.Width / 2, bounds.Height / 2);
brush.CenterColor = centercolor;
brush.SurroundColors = cPoints.Select(x => x.col).ToArray();
G.FillRectangle(brush, bounds);
}
- It starts with calculating the
CenterColor
- And setting the
CenterPoint
Next it creates a special
PathGradientBrush
using an overload that does not take aGraphicsPath
but aPoint
array!These points will correspond to the
SurroundColors
of the brush.
Especially the larger numbers could not be produced by my first idea of connecting the points along the edges with a simple LinearGradientBrush
. Many of those lines would miss the influence of the corners in between.
回答2:
Can't add a comment so adding a minor fix to @TaW solution:
Color centercolor = Color.FromArgb(r / c, r / c, r / c);
Should be
Color centercolor = Color.FromArgb(r / c, g / c, b / c);
来源:https://stackoverflow.com/questions/33415696/n-point-gradient-brush-polygon-fill