## Antialiased Bezier Curves

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

### Antialiased Bezier Curves

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.3Type TPoint    x As Single    y As SingleEnd TypeSub 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    NextEnd 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    LoopEnd SubScreenRes 600,600, 32, 1, &H40Randomize TimerLine (0,0)-(600,600),RGBA(255,255,255,255),BFRenderBezier (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, timPrint "Press any key to draw a continuous curve"SleepLine (0,0)-(600,600),RGBA(255,255,255,255),BFtim = timerFor 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 = cyNext iPrint "Time: " & Timer - timPrint "Press any key to draw 50 antialiased bezier curves of various widths, colors, and alphas."SleepLine (0,0)-(600,600),RGBA(255,255,255,255),BFFor 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 iSleep`
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:
AWESOME!!!
Veggiet
Posts: 156
Joined: Apr 17, 2006 19:41
Very nice, although it might be slow for a game it would be perfect for a drawing program. one thing:

Code: Select all

`'this lineIf 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:
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

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: 7433
Joined: May 28, 2005 3:28
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:
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: 2357
Joined: May 27, 2005 4:59
Contact:
Another program with good looking results. These are very nice man.
Posts: 469
Joined: Dec 17, 2006 23:37
Contact:
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 BezierDim as single t,Ptx,Pty,P0x,P1x,p2x,p3x,p0y,p1y,p2y,p3yDim as integer mousex,mousey,bouton,sens1,sens2,sensx,r,g,bsens1=1sens2=1sensx=1r=250g=50b=50Screenres 320,200,16,2P1x = 100P1y = 116p2x = 200p2y = 112p3x = 300p3y = 115p0x = 10p0y = 110Do        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: 5478
Joined: Sep 12, 2005 20:06
Location: Ohio, USA
I finally took a look at these and I must congratulate you on this. I love these curves :D
Posts: 469
Joined: Dec 17, 2006 23:37
Contact:
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:
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:
Filled bezier paths?
acetoline
Posts: 228
Joined: Oct 27, 2006 6:50
Contact:
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

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