沿着圆形 GraphicsPath 的 GDIPlus 渐变

发布于 2024-10-17 15:31:48 字数 417 浏览 4 评论 0原文

我的图形路径中有一个“甜甜圈”。

我想沿着该路径绘制渐变,并控制颜色何时以圆上给定的开始和结束角度开始和结束。

像这样:

http://www.andresilvadesign .com/wp-content/uploads/2011/01/Gauge-icon-design.jpg

LinearGradient 只能走一个角度,并且不能正确遵循路径。

PathGradientBrush 似乎只是..一个圆形渐变? 我似乎找不到在 C# 中正确执行此操作的方法。

任何帮助将不胜感激!

I have a "donut" in a graphics path.

I would like to draw a gradient along that path and control when a color starts and ends by a given start and end angle on the circle.

Like this:

http://www.andresilvadesign.com/wp-content/uploads/2011/01/Gauge-icon-design.jpg

A LinearGradient can only go one angle, and does not follow the path properly.

The PathGradientBrush seems to be just.. a circular gradient?
I cant seem to find a way to do this properly in C#.

Any help would be much appreciated!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

淡看悲欢离合 2024-10-24 15:31:48

您可以使用 PathGradientBrush 绘制一个完整的圆圈,然后对其进行遮罩,例如使用图像中的仪表面,或者使用背景颜色中的圆圈(和/或饼形楔形)?

Could you draw a full circle using the PathGradientBrush, then mask it, say with a gauge face like in the image, or with a circle (and/or pie wedge) in the background color?

朦胧时间 2024-10-24 15:31:48

我知道这已经很老了,作者可能不再关心了,但我在网上搜索了这个问题的答案,但找不到任何答案。

KeithS 评论中的链接 bobpowell.net/pgb。 htm 对我不起作用,因为我找不到一种方法来获取用于绘制曲线的实际点数。 (参见“让它们被包围”段落。)

为了尝试模拟色轮,我编写了这段代码:(我不是专业人士,非常欢迎任何增强代码的建议 - 特别是我的边缘有点模糊) 。

这个想法是产生一个看起来像甜甜圈的多边形,为每个“顶点”应用从颜色图插值的颜色,并将白色中心颜色放置在“虚拟”甜甜圈的中心。 (我使用双缓冲来避免闪烁。)

List<PointF> drawDonut(float angleA, float angleB, float width, int controlPointCount, float scaling, float centerX, float centerY)
    {
        List<PointF> points = new List<PointF>();
        if (controlPointCount < 2)
        {
            throw (new ArgumentOutOfRangeException("controlPointCount", "controlPointCount must be >1"));
        }
        if (width <= 0 || width > 100)
        {
            throw (new ArgumentOutOfRangeException("width", "width must be comprised between ]0:100]"));
        }

        List<float> angles = new List<float>();

        for (int i = 0; i < controlPointCount; i++)
        {
            angles.Add(angleA + (angleB - angleA) * (float)i / ((float)controlPointCount - 1.0f));
        }

        for (int i = 0; i < angles.Count; i++)
        {
            points.Add(new PointF((float)Math.Cos(angles[i]) * scaling + centerX, (float)Math.Sin(angles[i]) * scaling + centerY));
        }
        for (int i = 0; i < angles.Count; i++)
        {
            points.Add(new PointF(((100.0f - width) / 100.0f * (float)Math.Cos(angles[angles.Count - 1 - i])) * scaling + centerX, ((100.0f - width) / 100.0f * (float)Math.Sin(angles[angles.Count - 1 - i])) * scaling + centerY));
        }

        return points;
    }


    private List<Color> pieColor(Color[] MainColors, float[] mainStops, float[] stops)
    {
        List<Color> resultColors = new List<Color>();
        int index = 0;
        float percent;

        if (MainColors.Length != mainStops.Length)
        {
            throw new Exception("number of MainColors and mainStops must be the same");
        }


        if (MainColors.Length < 2)
        {
            for (int i = 0; i < stops.Length; i++)
            {
                resultColors.Add((MainColors.Length == 1) ? MainColors[0] : Color.White);
            }
        }
        else
        {
            for (int i = 0; i < stops.Length; i++)
            {
                index = Array.FindIndex(mainStops, x => x > stops[i]);
                if (index == 0)
                {
                    resultColors.Add(MainColors[0]);
                }
                else
                {
                    if (index == -1)
                    {
                        resultColors.Add(MainColors.Last());
                    }
                    else
                    {
                        percent = (stops[i] - mainStops[index - 1]) / (mainStops[index] - mainStops[index - 1]) * 100f;
                        resultColors.Add(alphaBlend(MainColors[index - 1], MainColors[index], percent));
                    }
                }
            }
        }

        return resultColors;
    }

    private Color alphaBlend(Color color1, Color color2, float percent)
    {

        byte R = (byte)(((float)color1.R * (100f - percent) / 100f) + ((float)color2.R * (percent) / 100f));
        byte G = (byte)(((float)color1.G * (100f - percent) / 100f) + ((float)color2.G * (percent) / 100f));
        byte B = (byte)(((float)color1.B * (100f - percent) / 100f) + ((float)color2.B * (percent) / 100f));
        return Color.FromArgb(R, G, B);
    }

    private void Form1_Paint(object sender, PaintEventArgs e)
    {
        RectangleF rec = e.ClipRectangle;
        float midx = rec.Width / 2;
        float midy = rec.Height / 2;
        float pieSize = (float)Math.Min(midx, midy) * 0.9f;
        float pieWidth = 5f;
        float angleA = -225;
        float angleB = 45;
        int nstops = (int)(Math.Abs(angleA - angleB) / 5 + 1);
        float[] stops;

        stops = new float[nstops];

        for (int i = 0; i < stops.Length; i++)
        {
            stops[i] = i * 100f / (stops.Length - 1);
        }

        List<PointF> myDonut = drawDonut(angleA * (float)Math.PI / 180f, angleB * (float)Math.PI / 180f, pieWidth, nstops, pieSize, midx, midy);

        List<Color> myColors = pieColor(new Color[] { Color.Red, Color.Yellow, Color.Green, Color.Cyan, Color.Blue, Color.Magenta, Color.Red },
                                        new float[] { 0.0f, 100f / 6f, 200f / 6f, 300f / 6f, 400f / 6f, 500f / 6f, 600f / 6f },
                                        stops);

        Color[] myPieColor = new Color[myDonut.Count];

        for (int i = 0; i < (myPieColor.Length / 2); i++)
        {
            myPieColor[i] = myColors[i];
            myPieColor[myPieColor.Length - i - 1] = myColors[i];
        }

        GraphicsPath gp = new GraphicsPath();
        gp.AddLines(myDonut.ToArray());
        e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
        using (PathGradientBrush b = new PathGradientBrush(gp))
        {
            b.CenterPoint = new PointF(midx, midy);
            b.CenterColor = Color.White;
            b.SurroundColors = myPieColor;

            e.Graphics.FillPath(b, gp);

        }
    }
}

I know this is quite old, and the author probably doesn't much care anymore, but I have searched the web for an answer to this question and I could not find any.

KeithS' link in the comment bobpowell.net/pgb.htm was not working for me because I could not find a way to get the real number of points used to draw the curve. (See the paragraph "Got them surrounded.")

To attempt to emulate the color wheel I thus wrote this code: (I am not a professional, any suggestion to enhance the code is very welcome - in particular my edges are a little fuzzy).

The idea was to produce a polygon that looks like a donut, apply a color for each "vertex" interpolated from a color map and a white centercolor placed in the center of the "virtual" donut. (I use doublebuffering to avoid flickering.)

List<PointF> drawDonut(float angleA, float angleB, float width, int controlPointCount, float scaling, float centerX, float centerY)
    {
        List<PointF> points = new List<PointF>();
        if (controlPointCount < 2)
        {
            throw (new ArgumentOutOfRangeException("controlPointCount", "controlPointCount must be >1"));
        }
        if (width <= 0 || width > 100)
        {
            throw (new ArgumentOutOfRangeException("width", "width must be comprised between ]0:100]"));
        }

        List<float> angles = new List<float>();

        for (int i = 0; i < controlPointCount; i++)
        {
            angles.Add(angleA + (angleB - angleA) * (float)i / ((float)controlPointCount - 1.0f));
        }

        for (int i = 0; i < angles.Count; i++)
        {
            points.Add(new PointF((float)Math.Cos(angles[i]) * scaling + centerX, (float)Math.Sin(angles[i]) * scaling + centerY));
        }
        for (int i = 0; i < angles.Count; i++)
        {
            points.Add(new PointF(((100.0f - width) / 100.0f * (float)Math.Cos(angles[angles.Count - 1 - i])) * scaling + centerX, ((100.0f - width) / 100.0f * (float)Math.Sin(angles[angles.Count - 1 - i])) * scaling + centerY));
        }

        return points;
    }


    private List<Color> pieColor(Color[] MainColors, float[] mainStops, float[] stops)
    {
        List<Color> resultColors = new List<Color>();
        int index = 0;
        float percent;

        if (MainColors.Length != mainStops.Length)
        {
            throw new Exception("number of MainColors and mainStops must be the same");
        }


        if (MainColors.Length < 2)
        {
            for (int i = 0; i < stops.Length; i++)
            {
                resultColors.Add((MainColors.Length == 1) ? MainColors[0] : Color.White);
            }
        }
        else
        {
            for (int i = 0; i < stops.Length; i++)
            {
                index = Array.FindIndex(mainStops, x => x > stops[i]);
                if (index == 0)
                {
                    resultColors.Add(MainColors[0]);
                }
                else
                {
                    if (index == -1)
                    {
                        resultColors.Add(MainColors.Last());
                    }
                    else
                    {
                        percent = (stops[i] - mainStops[index - 1]) / (mainStops[index] - mainStops[index - 1]) * 100f;
                        resultColors.Add(alphaBlend(MainColors[index - 1], MainColors[index], percent));
                    }
                }
            }
        }

        return resultColors;
    }

    private Color alphaBlend(Color color1, Color color2, float percent)
    {

        byte R = (byte)(((float)color1.R * (100f - percent) / 100f) + ((float)color2.R * (percent) / 100f));
        byte G = (byte)(((float)color1.G * (100f - percent) / 100f) + ((float)color2.G * (percent) / 100f));
        byte B = (byte)(((float)color1.B * (100f - percent) / 100f) + ((float)color2.B * (percent) / 100f));
        return Color.FromArgb(R, G, B);
    }

    private void Form1_Paint(object sender, PaintEventArgs e)
    {
        RectangleF rec = e.ClipRectangle;
        float midx = rec.Width / 2;
        float midy = rec.Height / 2;
        float pieSize = (float)Math.Min(midx, midy) * 0.9f;
        float pieWidth = 5f;
        float angleA = -225;
        float angleB = 45;
        int nstops = (int)(Math.Abs(angleA - angleB) / 5 + 1);
        float[] stops;

        stops = new float[nstops];

        for (int i = 0; i < stops.Length; i++)
        {
            stops[i] = i * 100f / (stops.Length - 1);
        }

        List<PointF> myDonut = drawDonut(angleA * (float)Math.PI / 180f, angleB * (float)Math.PI / 180f, pieWidth, nstops, pieSize, midx, midy);

        List<Color> myColors = pieColor(new Color[] { Color.Red, Color.Yellow, Color.Green, Color.Cyan, Color.Blue, Color.Magenta, Color.Red },
                                        new float[] { 0.0f, 100f / 6f, 200f / 6f, 300f / 6f, 400f / 6f, 500f / 6f, 600f / 6f },
                                        stops);

        Color[] myPieColor = new Color[myDonut.Count];

        for (int i = 0; i < (myPieColor.Length / 2); i++)
        {
            myPieColor[i] = myColors[i];
            myPieColor[myPieColor.Length - i - 1] = myColors[i];
        }

        GraphicsPath gp = new GraphicsPath();
        gp.AddLines(myDonut.ToArray());
        e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
        using (PathGradientBrush b = new PathGradientBrush(gp))
        {
            b.CenterPoint = new PointF(midx, midy);
            b.CenterColor = Color.White;
            b.SurroundColors = myPieColor;

            e.Graphics.FillPath(b, gp);

        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文