简体   繁体   English

如何使用图形 class c# 绘制彩虹线

[英]How to draw a rainbow line using Graphic class c#

So i'm trying to create infinite rainbow line.所以我正在尝试创造无限的彩虹线。 Here ColorUtils class How do I get a rainbow color gradient in C#?这里 ColorUtils class 如何在 C# 中获得彩虹色渐变? (I'm using Framework 4.7.3 (我正在使用框架 4.7.3

    int rainbowStage = 0;
    int rainbowNext = 0;

    private void Form1_Paint(object sender, PaintEventArgs e)
    {
        BackgroundWorker worker = new BackgroundWorker();

        PointF point1 = new PointF(100.0F, 100.0F);
        PointF point2 = new PointF(235.0F, 100.0F);

        worker.DoWork += async delegate (object s, DoWorkEventArgs args)
        {
            do
            {
                Console.WriteLine(await getRainbow());
                rainbowNext++;
                Pen pen = new Pen(await getRainbow(), 3);
                e.Graphics.DrawLine(pen, point1, point2);
                e.Graphics.Clear(Color.FromArgb(26, 26, 26));
            } while (rainbowStage == rainbowNext);
        };

        worker.RunWorkerCompleted += delegate (object s, RunWorkerCompletedEventArgs args)
        {
            rainbowStage++;
        };
    }

    async Task<ColorUtils.ColorRGB> getRainbow()
    {
        for (double i = 0; i < 1; i += 0.01)
        {
            ColorUtils.ColorRGB c = ColorUtils.HSL2RGB(i, 0.5, 0.5);
            return c;
        }
        ColorUtils.ColorRGB c1 = ColorUtils.HSL2RGB(0, 0.5, 0.5);
        return c1;
    }

So, you have found how to generate a sequence of rainbow colors.因此,您已经找到了如何生成彩虹序列 colors。 But your code is not actually correct, it should be something like:但是您的代码实际上并不正确,它应该类似于:

IEnumerable<Color> GetRainbow()
{
    for (double i = 0; i < 1; i += 0.1)
    {
        Color c = ColorUtils.HSL2RGB(i, 0.5, 0.5);
        yield return c;
    }
}

That will give you a sequence of ten colors, using the actual color type used by winforms.这将为您提供十个 colors 的序列,使用 winforms 使用的实际颜色类型

To draw the rainbow we need to draw each color as a separate line, slightly offset from each other.要绘制彩虹,我们需要将每种颜色绘制为单独的线,彼此略微偏移。 To get the offset we need to do some vector math:为了得到偏移量,我们需要做一些向量数学:

var dir = point1 - point2;
var offset= new PointF(dir.Y, -dir.X).Normalize();
...
public static PointF Normalize(this PointF A)
{
    float distance = Math.Sqrt(A.X * A.X + A.Y * A.Y);
    return new PointF(A.X / distance, A.Y / distance);
}
public static PointF Mul(this PointF a, float b)
{
    return new PointF(a.X * b, a.Y * b);
}

We can then begin drawing our line:然后我们就可以开始画线了:

var colors = GetRainbow().ToList();
var width = 10f / colors.Count;
for(int i = 0; i < colors.Count; i++){
    using var pen = new Pen(colors[i], width);
    var o = offset.Mul( width * i)
     e.Graphics.DrawLine(pen, point1 + o, point2 + o);
}

That should give you a rainbow line of with 10 with one pixel per color, adjust the width literal to get a wider line.这应该会给你一条 10 条彩虹线,每种颜色一个像素,调整宽度文字以获得更宽的线。

An alternative approach would be to create something like a texture brush displaying the rainbow and use that for drawing.另一种方法是创建类似纹理画笔的东西来显示彩虹并将其用于绘图。

Note that all drawing code need to be run on the UI thread, and any other calculations are really fast, they just involve a handful of simple math operations.请注意,所有绘图代码都需要在 UI 线程上运行,任何其他计算都非常快,它们只涉及一些简单的数学运算。 So there is nothing at all to be gained from trying to run anything on any background thread.因此,尝试在任何后台线程上运行任何东西都没有任何收获。

Here's a copy, paste, run, version of what you're trying to do:这是您尝试执行的操作的复制、粘贴、运行版本:

public class Form1 :  Form
{
    public Form1()
    {
        this.Paint += Form1_Paint;
    }
    
    private void Form1_Paint(object sender, PaintEventArgs e)
    {
        foreach (var rgb in GetRainbow().Select((colour, indexer) => (colour, indexer)))
        {
            Console.WriteLine(rgb.colour);
            using (Pen pen = new Pen(rgb.colour, 3))
            {
                e.Graphics.DrawLine(pen, new PointF(100.0F, 100.0F + rgb.indexer), new PointF(235.0F, 100.0F + rgb.indexer));
            }
        }
    }

    IEnumerable<ColorRGB> GetRainbow()
    {
        for (double i = 0; i < 1; i += 0.01)
        {
            yield return HSL2RGB(i, 0.5, 0.5);
        }
    }

    public struct ColorRGB
    {
        public byte R;
        public byte G;
        public byte B;

        public ColorRGB(Color value)
        {
            this.R = value.R;
            this.G = value.G;
            this.B = value.B;
        }

        public static implicit operator Color(ColorRGB rgb)
        {
            Color c = Color.FromArgb(rgb.R, rgb.G, rgb.B);
            return c;
        }

        public static explicit operator ColorRGB(Color c)
        {
            return new ColorRGB(c);
        }
    }

    public static ColorRGB HSL2RGB(double h, double sl, double l)
    {
        double v;
        double r, g, b;

        r = l;   // default to gray
        g = l;
        b = l;
        v = (l <= 0.5) ? (l * (1.0 + sl)) : (l + sl - l * sl);
        if (v > 0)
        {
            double m;
            double sv;
            int sextant;
            double fract, vsf, mid1, mid2;

            m = l + l - v;
            sv = (v - m) / v;
            h *= 6.0;
            sextant = (int)h;
            fract = h - sextant;
            vsf = v * sv * fract;
            mid1 = m + vsf;
            mid2 = v - vsf;
            switch (sextant)
            {
                case 0:
                    r = v;
                    g = mid1;
                    b = m;
                    break;
                case 1:
                    r = mid2;
                    g = v;
                    b = m;
                    break;
                case 2:
                    r = m;
                    g = v;
                    b = mid1;
                    break;
                case 3:
                    r = m;
                    g = mid2;
                    b = v;
                    break;
                case 4:
                    r = mid1;
                    g = m;
                    b = v;
                    break;
                case 5:
                    r = v;
                    g = m;
                    b = mid2;
                    break;
            }
        }
        ColorRGB rgb;
        rgb.R = Convert.ToByte(r * 255.0f);
        rgb.G = Convert.ToByte(g * 255.0f);
        rgb.B = Convert.ToByte(b * 255.0f);
        return rgb;
    }
}

When run, I get this:运行时,我得到这个:

表格1

There were too many things going wrong with your original code, but don't use async / await , don't forget to dispose disposables, don't forget to compute the actual line you're trying to draw, use yield return to get your rainbow colours, etc.您的原始代码有太多问题,但不要使用async / await ,不要忘记处理一次性用品,不要忘记计算您要绘制的实际线,使用yield return来获取你的彩虹色等

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM