N-point gradient brush polygon fill

拈花ヽ惹草 提交于 2020-01-30 06:26:29

问题


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 a GraphicsPath but a Point 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!