Antialiased Bezier Curves

Source-code only - please, don't post questions here.
acetoline
Posts: 228
Joined: Oct 27, 2006 6:50
Contact:

Antialiased Bezier Curves

Postby acetoline » Jan 12, 2007 13:59

After a little playing around and experimenting with ways that my anti-aliased circles could be used, I came up with this program to draw (very) pretty anti-aliased bezier curves.
It took three hours off of my life to write this prog and perfect it; enjoy!

It looks beautifully smooth, thanks to the algorithm it uses. The main problem it has is speed.

Note that the code is NOT optimized, so it probably isn't suitable for anything that requires more than a few curves.

Code: Select all

'just some simple code for drawing beziers.
#Define Dist(p1, p2) (Sqr((p1.x-p2.x)^2 + (p1.y-p2.y)^2))

'you can play with this variable to adjust the additional accuracy.
'minus values = more speed, less accurate.
'positive values =less speed, more accurate.
'Values beyond 2 have no effect.
Const ACCURACY_OVERKILL = -0.3

Type TPoint
    x As Single
    y As Single
End Type

Sub DrawDot(ByVal x As Single, ByVal y As Single, radius As Single, r As uByte, g As uByte, b As uByte, a As uByte)
    Dim d As Single
    Dim As Single px,py
    Dim As Single rad2
    DIm As Single cr
    Dim As Single x1,y1,x2,y2
    'Print y
   
    If a > 255 Then a = 255
   
    cr=(radius/1.5)
    x1 = Int(x-radius-ACCURACY_OVERKILL)
    y1 = Int(y-radius-ACCURACY_OVERKILL)
    x2 = Int(x+radius+ACCURACY_OVERKILL)
    y2 = Int(y+radius+ACCURACY_OVERKILL)
   
    For py= y1 To y2
        For px = x1 To x2
            d = Sqr(((px-x)^2)+((py-y)^2))
            d = d / radius
            If d < 1 Then
                d ^= cr
                Line(px, py)-(px, py),RGBA(r,g,b,a*(1-d)),BF
            End If
        Next
    Next
End Sub

'this is an adaptive algorithm that I discovered myself.
'TODO: make it smarter when working with widths.
Sub RenderBezier (p1 As TPoint, p2 As TPoint, p3 As TPoint, p4 As TPoint, lwidth As Single, r As uByte, g As uByte, b As uByte, alpha As uByte)
    Dim t As Single = 1 'the most important value in the whole procedure
    Dim vert As Single = 0
    Dim binc As Single
    Dim bdist As Single
    Dim cp As TPoint
    Dim lp As TPoint
    Dim c As Integer=0
    'calculate the base increment (binc) using the base distance (bdist).
    'I'm too lazy to conjure up a direct algorithm to do this.
    'I just use a converging loop.
    binc = 0.3
    For i As Integer = 1 To 10 'don't do an infinite loop if it doesn't seem to converge.
        t = binc
        cp.x = p1.x*(1-t)^3 + 3*p2.x*((1-t)^2)*t + 3*p3.x*(1-t)*(t^2) + p4.x*(t^3)
        cp.y = p1.y*(1-t)^3 + 3*p2.y*((1-t)^2)*t + 3*p3.y*(1-t)*(t^2) + p4.y*(t^3)
        bdist = Dist(cp, p1)
        binc /= bdist
        If (1 > (bdist - 0.02)) And (1 < (bdist + 0.02)) Then Exit For 'converged. yay!
    Next i
   
    'Now, just go up the curve, adjusting the base increment whenever necessary.
    t = 0
    Do Until (t > 1)
        vert = 1-t
        cp.x = p1.x*vert^3 + 3*p2.x*vert*vert*t + 3*p3.x*vert*t*t + p4.x*(t^3)
        cp.y = p1.y*vert^3 + 3*p2.y*vert*vert*t + 3*p3.y*vert*t*t + p4.y*(t^3)
       
        bdist = Dist(cp, lp)
        binc /= bdist

        If (lwidth <= 1.5) Or (c=0) Then DrawDot (cp.x, cp.y, lwidth, r, g, b, 2*alpha/lwidth)
        lp.x = cp.x
        lp.y = cp.y
        t += binc
        c = 1-c
    Loop
End Sub


ScreenRes 600,600, 32, 1, &H40
Randomize Timer

Line (0,0)-(600,600),RGBA(255,255,255,255),BF

RenderBezier (type<TPoint>(100,100), type<TPoint>(300,100), type<TPoint>(300,300), type<TPoint>(500,300), _
                    1.1, 0,0,0,255)
Dim As Single cx, cy, lx, ly, ctx, cty, ltx, lty, tim

Print "Press any key to draw a continuous curve"
Sleep
Line (0,0)-(600,600),RGBA(255,255,255,255),BF
tim = timer
For i As Integer = 0 To 20
    cy = 600 * rnd
    cx = 600 * rnd
    ctx = (200 * rnd) - 100
    cty = (200 * rnd) - 100
    RenderBezier (type<TPoint>(lx,ly), type<TPoint>(lx-ltx,ly-lty), type<TPoint>(cx+ctx,cy+cty), type<TPoint>(cx,cy), _
                    1.4, 0,0,0,255)
    ltx = ctx: lty = cty
    lx = cx: ly = cy
Next i
Print "Time: " & Timer - tim

Print "Press any key to draw 50 antialiased bezier curves of various widths, colors, and alphas."
Sleep
Line (0,0)-(600,600),RGBA(255,255,255,255),BF
For i As Integer = 0 To 50
    RenderBezier (type<TPoint>(600*rnd,600*rnd), type<TPoint>(600*rnd,600*rnd), type<TPoint>(600*rnd,600*rnd), type<TPoint>(600*rnd,600*rnd), _
                    1+(2*Rnd), 255*rnd, 255*rnd, 255*rnd, 155+(100*rnd))
Next i
Sleep
Last edited by acetoline on Jan 12, 2007 16:09, edited 1 time in total.
relsoft
Posts: 1767
Joined: May 27, 2005 10:34
Location: Philippines
Contact:

Postby relsoft » Jan 12, 2007 15:21

AWESOME!!!
Veggiet
Posts: 156
Joined: Apr 17, 2006 19:41

Postby Veggiet » Jan 12, 2007 15:54

Very nice, although it might be slow for a game it would be perfect for a drawing program. one thing:

Code: Select all

'this line
If alpha > 255 Then alpha = 255
'returns an implicit variable allocation. I'm not sure but I guess it should be:
If a > 255 Then a = 255
duke4e
Posts: 717
Joined: Dec 04, 2005 0:16
Location: Varazdin, Croatia, Europe
Contact:

Postby duke4e » Jan 12, 2007 16:34

Just wait till Joshy sees this, I'm sure he'll give you plenty speed optimization tips ;)
DNAarray
Posts: 29
Joined: May 15, 2006 21:17

good job

Postby DNAarray » Jan 12, 2007 20:09

The next step is really a tough one, an anti-alised scalable font using 100% basic code, thus you would never need to use ttf libraries and the font could be usable by linux or windows. I have been playing around trying to do this. I think will try fuzzycircle(x,y,radius,alpha) where x and y are real numbers and if say x is a 1.4, it would randomly choose 1 60% of the time and 2 40% of the time. Thus you define about 20 points for a font symbol, and a scale, and the routine randomly draws circles where the font should be. Maybe I should stick with non scalable fuzzypset(x,y,alpha) for a test.

Anyways great job!
D.J.Peters
Posts: 7191
Joined: May 28, 2005 3:28

Postby D.J.Peters » Jan 12, 2007 23:18

Hello acetoline
more of this (good) stuff and your first 2d drawing / painting application are borne. :-)

Joshy
acetoline
Posts: 228
Joined: Oct 27, 2006 6:50
Contact:

Postby acetoline » Jan 13, 2007 13:08

Thanks for the feedback, guys!

Veggiet: yes, that line doesn't work. Actually, it's reduntant (a is already a ubyte, how could it be >255?) so you can just delete it altogether.

I also realized that there is a slight glitch in the program. I fixed it, and then I realized that it looked better without the fix. Funny how a glitch actually caused the curves to look better. Needless to say, the bug is going to become a feature ;)
Dr_D
Posts: 2345
Joined: May 27, 2005 4:59
Contact:

Postby Dr_D » Jan 13, 2007 22:23

Another program with good looking results. These are very nice man.
Hezad
Posts: 469
Joined: Dec 17, 2006 23:37
Contact:

Postby Hezad » Jan 23, 2007 12:48

i had to try to code those bezier curves ^^

(Did you know Bezier was a Renault engineer? He worked on those curves to make the shape of the car body!)

Here is a bezier curve ^^ It's not antialiased but you can change the shape with the controlling points.

Code: Select all

'' Courbes de Bezier

Dim as single t,Ptx,Pty,P0x,P1x,p2x,p3x,p0y,p1y,p2y,p3y
Dim as integer mousex,mousey,bouton,sens1,sens2,sensx,r,g,b
sens1=1
sens2=1
sensx=1
r=250
g=50
b=50

Screenres 320,200,16,2

P1x = 100
P1y = 116
p2x = 200
p2y = 112
p3x = 300
p3y = 115
p0x = 10
p0y = 110

Do
   
    Screenset 1,0
    CLS
   
    '' Contours et points de controle
    Line (p0x,p0y)-(p1x,p1y),rgb(120,120,120)
    Line (p1x,p1y)-(p2x,p2y),rgb(120,120,120)
    Line (p2x,p2y)-(p3x,p3y),rgb(120,120,120)
   
    Line (p0x-2,p0y-2)-(p0x+2,p0y+2),rgb (150,150,150),bf
    Line (p1x-2,p1y-2)-(p1x+2,p1y+2),rgb (150,150,150),bf
    Line (p2x-2,p2y-2)-(p2x+2,p2y+2),rgb (150,150,150),bf
    Line (p3x-2,p3y-2)-(p3x+2,p3y+2),rgb (150,150,150),bf

    '' Interaction
   
    Getmouse mousex,mousey,,bouton
   
    if bouton and 1 then
    if mousex<=p0x + 20 and mousex>=p0x - 20 then
        if mousey<=p0y + 20 and mousey>=p0y - 20 then
            P0x = mousex
            P0y = mousey
        end if
    end if
   
    if mousex<=p1x + 20 and mousex>=p1x - 20 then
        if mousey<=p1y + 20 and mousey>=p1y - 20 then
            P1x = mousex
            P1y = mousey
        end if
    end if
   
    if mousex<=p2x + 20 and mousex>=p2x - 20 then
        if mousey<=p2y + 20 and mousey>=p2y - 20 then
            P2x = mousex
            P2y = mousey
        end if
    end if
   
    if mousex<=p3x + 20 and mousex>=p3x - 20 then
        if mousey<=p3y + 20 and mousey>=p3y - 20 then
            P3x = mousex
            P3y = mousey
        end if
    end if
   
    end if

    '' Mouvement local
       
        'P1y+=1*sens1
        'P2y+=1*sens2
       
        'if p1y>195 or p1y<5 then sens1=-sens1
        'if p2y>140 or p2y<50 then sens2=-sens2
   
    '' Affichage

    For t = 0 to 1 step 0.001   
        Ptx = P0x * ((1 - t)^3) + 3 * P1x * t * ((1 - t)^2) + 3 * P2x * (t^2) * (1 - t) + P3x * (t^3)
        Pty = P0y * ((1 - t)^3) + 3 * P1y * t * ((1 - t)^2) + 3 * P2y * (t^2) * (1 - t) + P3y * (t^3)
        r=p2y+(t*100)
        g=p1y+(t*100)
        if r>255 then r=255
        if g>255 then g=255
        Circle(Ptx, Pty),2,rgb(r,g,b),,,,f
    next

    Screensync
    Screencopy
   
loop until multikey(&h01)
Pritchard
Posts: 5425
Joined: Sep 12, 2005 20:06
Location: Ohio, USA

Postby Pritchard » Jan 23, 2007 12:57

I finally took a look at these and I must congratulate you on this. I love these curves :D
Hezad
Posts: 469
Joined: Dec 17, 2006 23:37
Contact:

Postby Hezad » Jan 23, 2007 13:04

Thanks :)

The curves are not so difficult to code, you just have to know the equation (I got them on wikipedia) and make the control points "controllable" by the mouse :)
But this one was just a little test, the acetoline version is far better :) I even don't know how to do antialiasing ^^

Next step : The same in 3D :)
acetoline
Posts: 228
Joined: Oct 27, 2006 6:50
Contact:

Postby acetoline » Jan 24, 2007 6:00

Thank you all for your comments. Right now I'm experimenting with filled bezier paths and such.
There are so few good resources on the web for quality graphics. When I have the time, I might write a set of tutorials or something ;)
relsoft
Posts: 1767
Joined: May 27, 2005 10:34
Location: Philippines
Contact:

Postby relsoft » Jan 24, 2007 11:59

Filled bezier paths?
acetoline
Posts: 228
Joined: Oct 27, 2006 6:50
Contact:

Postby acetoline » Jan 24, 2007 14:49

Filled bezier paths?


Yeah, those cool shapes you get when you take a bunch of beziers, connect them to form a path, and then fill them.
loul
Posts: 12
Joined: Jul 17, 2006 2:27

Help implementing your Bezier Crurves

Postby loul » Jun 17, 2007 16:39

As a beginning programmer (age 71) I need a little help implementing your Beziers. What I want to do is use arrays of various lengths as input data for the curves (sort of like the curves for a stock) and while the B-Splines might be best, the Beziers should do. The "X" increment would be a constant 1 and of course the "Y" increment varies with the data. The Curve would have varying numbers of data points, say from 7 to 37. My problem is, where do I plug in the constants for the data points?

Thanks for any suggestions.

lou howard

Return to “Tips and Tricks”

Who is online

Users browsing this forum: No registered users and 1 guest