Bezier function

the function bezier draws a spike on the inside of the curve when it creates an infinitesimally small loop.

note: this spike is also on the outside of the loop if lineJoin(MITER) but this is expected.

@Amber Welcome to the forum. It’s good to have more users finding things wrong in the new version so they can be corrected.

1 Like

Thought I’d try the bezier function. I was able to get the spike inside and outside just using the bezier function, no lineJoin. Not sure what lineJoin does.

Hmmm, interesting. This is probably due to some kind of precision issue / singularity with this specific edge case. What does the code look like for this?

@John Here’s the code I used for mine. Just touch a circle to move it.

viewer.mode=FULLSCREEN

function setup()
    tab={100,100,100,200,200,100,200,200}
end

function draw()
    background(0)
    style.noFill()
    style.stroke(255)
    style.strokeWidth(4)
    bezier(tab[1],tab[2],tab[3],tab[4],tab[5],tab[6],tab[7],tab[8])
    for z=1,8,2 do
        ellipse(tab[z],tab[z+1],20)
    end
end

function touched(t)
    for z=1,8,2 do
        if t.x>tab[z]-20 and t.x<tab[z]+20 and t.y>tab[z+1]-20 and t.y<tab[z+1]+20 then
            tab[z]=t.x
            tab[z+1]=t.y
        end
    end
end
1 Like

my code is similar, just more complicated hahah
lineJoin() is a new style setting that sets how polylines corners look.
it seems MITER is the default setting for it.

1 Like

This is cool to have an integrated bezier curves in Codea, must be better than my lua only version.

It would be nice to have a version that compute instead of just drawing it. It will allow us to make something follow the path.

I did something that do it by compute and cache the segments (like Godot).

Path.zip (2.3 KB)

While we’re on the subject of bezier, I just put this together. It draws a Bézier curve using any number of points that you want to enter in the tables px and py. Tap on a point to move it. If you want the point values that make up the curve, they’re in the table tab. This is for the Legacy 3.x code.

PS. I modified the code to calculate 12 pairs of random points. You get a different curve each time it’s run. You can change the 12 in the for loop to whatever number you want to try.

viewer.mode=FULLSCREEN

function setup()
    px,py={},{}
    for z=1,12 do
        table.insert(px,math.random(WIDTH))
        table.insert(py,math.random(HEIGHT))
    end
    step=.01
    n=#px-1
    bez()
end

function bez()
    tab={}
    for r=0,1,step do
        pX,pY=0,0
        for i=0,n do
            pX=pX+calc1(n,i,px[i+1],r)
            pY=pY+calc1(n,i,py[i+1],r)
        end
        table.insert(tab,vec2(pX,pY))
    end
    table.insert(tab,vec2(px[#px],py[#py]))
end

function draw()
    background(31, 59, 60)
    stroke(255)
    strokeWidth(4)
    fill(255)
    for z=2,#tab do
        line(tab[z-1].x,tab[z-1].y,tab[z].x,tab[z].y)
    end 
    stroke(0,255,0) 
    fill(0,255,0)
    for z=2,#px-1 do
        ellipse(px[z],py[z],15)
    end
    stroke(0,0,255) 
    fill(0,0,255)
    ellipse(px[1],py[1],15)
    ellipse(px[#px],py[#py],15)
    stroke(255,0,0)
    strokeWidth(1)
    for z=2,#px do
        line(px[z-1],py[z-1],px[z],py[z])
    end
end

function calc1(n,i,p,t)
     return(fac(n)/(fac(i)*fac(n-i))*(1-t)^(n-i)*t^i*p)
end

function fac(n)
    return n > 0 and n * fac(n-1) or 1
end

function touched(t)
    if t.state==BEGAN then
        offset=0
        for z=1,#px do
            if math.abs(t.x-px[z])<30 and math.abs(t.y-py[z])<30 then
                offset=z
            end
        end
    elseif t.state==CHANGED then
        px[offset]=t.x
        py[offset]=t.y
        bez()
    end
end

Here’s my bézier code (for Codea 3) which includes evaluation routines (and tangent, and splitting, amongst others). It uses a mesh to render the curve, which provides for a smoother render than line segments.

(Incidentally, @dave1707, there are much more efficient ways to compute the coefficients of Pascal’s triangle than using factorials)

@LoopSpace Thanks. When I wrote the code, I didn’t realize that part was calculating the coefficients of Pascal’s triangle. I was just using a Bezier formula I found on the internet and converted it to run in Codea. I originally wrote code long ago that used 4 points for the Bézier curve, but I wanted to use a varying number of points.

I found this site that gave a formula and explained it a little.

https://www.freecodecamp.org/news/nerding-out-with-bezier-curves-6e3c0bc48e2f/

Apart from the initial bit about “math anxiety”, that’s actually not a bad article.

I thought this was a pretty good video on splines

3 Likes

@sim Looks like an interesting video. Watched a few minutes. Will watch more of it when I have time.

1 Like

A slightly different approach using Catmull-Rom splines so that the curve passes through known control points. You can move the control points and then save the required path data for use in other programs.

Spline.zip (2.5 KB)

2 Likes

@timber Interesting program. Thanks for posting it.

There’s also a nice algorithm due to someone called John Hobby (who worked with Don Knuth on font design, I believe) that produces a sequence of cubic bézier curves passing through a sequence of points that is designed to be “nice” at the joins. There’s an implementation of it in my bézier code (core function starts on line 371). I also modified it to something I call a “Quick Hobby” algorithm which is also in that library.

2 Likes