简体   繁体   中英

How to draw a linear gradient circle in .NET?

Haw can I draw a circle like this in VB.NET or in C#?

在此处输入图片说明

You can approximate the ring with lots of trapezoids, and use a different fill colour for each rectangle.

Imports System.Drawing.Drawing2D

Public Class Form1

    Private Sub Form1_Paint(sender As Object, e As PaintEventArgs) Handles MyBase.Paint

        Dim centre = New PointF(160, 140)
        Dim r1 = 100
        Dim r2 = 105

        Dim colourStart = 90 * Math.PI / 180

        Dim col1 As Color
        col1 = Color.FromArgb(0, 0, 0)

        e.Graphics.SmoothingMode = SmoothingMode.AntiAlias

        Using br As New SolidBrush(col1)

            Dim nSteps = 180
            Dim aInc = 2 * Math.PI / nSteps

            For i = 0 To nSteps - 1
                Dim a = i * aInc

                Dim t1 = a
                Dim t2 = a + aInc

                Dim p1 = New PointF(CSng(r2 * Math.Cos(t1)) + centre.X, CSng(r2 * Math.Sin(t1)) + centre.Y)
                Dim p2 = New PointF(CSng(r1 * Math.Cos(t1)) + centre.X, CSng(r1 * Math.Sin(t1)) + centre.Y)
                Dim p3 = New PointF(CSng(r1 * Math.Cos(t2)) + centre.X, CSng(r1 * Math.Sin(t2)) + centre.Y)
                Dim p4 = New PointF(CSng(r2 * Math.Cos(t2)) + centre.X, CSng(r2 * Math.Sin(t2)) + centre.Y)

                Dim pts = {p1, p2, p3, p4}

                col1 = HSL2RGB(a + colourStart, 1, 0.5)
                br.Color = col1

                e.Graphics.FillPolygon(br, pts)

            Next

        End Using

    End Sub

    ' HSL2RGB from https://dotnetfiddle.net/aORkec (with translation and bugfix).
    ''' <summary>
    ''' Convert HSL to RGB.
    ''' </summary>
    ''' <param name="h">Hue 0..2pi</param>
    ''' <param name="s">Saturation 0..1</param>
    ''' <param name="l">Lightness 0..1</param>
    ''' <returns>RGB color.</returns>
    <DebuggerHidden>
    Function HSL2RGB(h As Double, s As Double, l As Double) As Color
        If h > 2 * Math.PI Then h -= 2 * Math.PI
        If h < 0 Then h += 2 * Math.PI

        h = h / (2 * Math.PI)
        Dim v As Double

        Dim r, g, b As Double
        r = l
        g = l
        b = l
        v = If(l <= 0.5, l * (1.0 + s), l + s - l * s)

        If (v > 0) Then
            Dim m As Double
            Dim sv As Double
            Dim sextant As Integer
            Dim fract, vsf, mid1, mid2 As Double
            m = l + l - v
            sv = (v - m) / v
            h *= 6.0
            sextant = CInt(Math.Floor(h))
            fract = h - sextant
            vsf = v * sv * fract
            mid1 = m + vsf
            mid2 = v - vsf
            Select Case sextant
                Case 0, 6
                    r = v
                    g = mid1
                    b = m
                Case 1
                    r = mid2
                    g = v
                    b = m
                Case 2
                    r = m
                    g = v
                    b = mid1
                Case 3
                    r = m
                    g = mid2
                    b = v
                Case 4
                    r = mid1
                    g = m
                    b = v
                Case 5
                    r = v
                    g = m
                    b = mid2
            End Select
        End If

        Return Color.FromArgb(Convert.ToByte(r * 255.0F), Convert.ToByte(g * 255.0F), Convert.ToByte(b * 255.0F))

    End Function

End Class

Result:

彩环

Better results could probably be achieved by using a Brush which allows a colour gradient in the correct direction for each rectangle.


It is also possible to make the circle from annular sectors, which gives accurate bounds instead of the straight edges of trapezoids:

    Function Rad2Deg(x As Double) As Single
        Return Convert.ToSingle(x * 180 / Math.PI)
    End Function

    Private Sub Form1_Paint(sender As Object, e As PaintEventArgs) Handles MyBase.Paint

        Dim centreF = New PointF(160, 140)
        Dim centre = New Point(CInt(centreF.X), CInt(centreF.Y))
        Dim r1 = 100
        Dim r2 = 105

        Dim boundingRectInner = New Rectangle(-r1, -r1, r1 * 2, r1 * 2)
        boundingRectInner.Offset(centre)

        Dim boundingrectOuter = New Rectangle(-r2, -r2, r2 * 2, r2 * 2)
        boundingrectOuter.Offset(centre)

        Dim colourStart = 90 * Math.PI / 180

        Dim col1 As Color
        col1 = Color.FromArgb(0, 0, 0)

        e.Graphics.SmoothingMode = SmoothingMode.AntiAlias

        Using br As New SolidBrush(col1)

            Dim nSteps = 12
            Dim aInc = 2 * Math.PI / nSteps
            Dim sweepAngle = Rad2Deg(aInc)

            For i = 0 To nSteps - 1
                Dim a = i * aInc

                Dim t1 = a
                Dim t2 = a + aInc

                Dim p3 = New PointF(CSng(r1 * Math.Cos(t2)) + centreF.X, CSng(r1 * Math.Sin(t2)) + centreF.Y)
                Dim p4 = New PointF(CSng(r2 * Math.Cos(t2)) + centreF.X, CSng(r2 * Math.Sin(t2)) + centreF.Y)

                Using gp As New GraphicsPath()
                    gp.AddArc(boundingRectInner, Rad2Deg(a), sweepAngle)
                    gp.AddLine(p3, p4)
                    gp.AddArc(boundingrectOuter, Rad2Deg(a + aInc), -sweepAngle)
                    gp.CloseFigure()

                    col1 = HSL2RGB(a + colourStart, 1, 0.5)
                    br.Color = col1

                    e.Graphics.FillPath(br, gp)
                End Using

            Next

        End Using

    End Sub

Note the smaller number of steps, so the colours are fewer, yet the edges are still those of a circle:

在此处输入图片说明

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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