Splines!

Showcase your libraries, tools and other projects that help your fellow love users.
User avatar
vrld
Party member
Posts: 917
Joined: Sun Apr 04, 2010 9:14 pm
Location: Germany
Contact:

Splines!

Post by vrld »

I was really really bored today, so I implemented Bézier curves for LÖVE. If you want to use them in your own projects, you need both bezier.lua and vector.lua.
The "api":
Bezier.new(points)
Creates a new Bézier curve. Points is a table of x,y pairs defining the control polygon of the curve.
Example:

Code: Select all

b = Bezier.new{10,400, 100,100, 400,90, 490,380}
Bezier:clone()
Returns an identical curve.

Bezier:Bezier:controlPolygon(min,max)
Returns the control points from min to max. If min and max are omitted, they default to min = 1, max = all.
This in addition with unpack() can be used to draw the control polygon:
Example

Code: Select all

love.graphics.line(unpack(b:controlPolygon())
Bezier:eval(t)
Evaluate the curve with parameter t. t has to fulfill 0 <= t <= 1. This can be used to move an actor on a Bézier-path.

Bezier:degreeUp()
Increases the degree of the curve, that is #control-points - 1. It returns nothing and alters the current bezier-curve.

Bezier:subdivide(t)
Subdivide the curve with weight t. If t is omitted, it defaults to 0.5. The subdivided curve is returned.
Subdivision is the core of the drawing routine.
Example

Code: Select all

b = b:subdivide(.8) -- will subdivide the curve with more points to the end
Bezier:derivation()
Returns the derivation of the curve. The derivation is one degree lower than the original curve. Not sure how you may want to use this, but included it anyway ;)

Bezier:polygon(k)
Returns an approximation to the Bézier-curve. If k is omitted, it defaults to 3. 3 to 5 is usually a good choice for visualizing the curve.
Example

Code: Select all

polygon = b:polygon(4)
function love.graphics.draw()
    love.graphics.line(unpack(polygon))
end
Bezier:draw(k)
Draws the curve. As this evaluates Bezier:polygon(k), you should really not use this with a combination of high k and degree of the curve. Use the above instead.

I also attached a demo where you can play with the different functions. Have fun ;)

Next item on the is B-Spline curves (with interpolating and periodic b-splines. Stay tuned)

See attachment below
Last edited by vrld on Sun Jun 20, 2010 12:23 pm, edited 2 times in total.
I have come here to chew bubblegum and kick ass... and I'm all out of bubblegum.

hump | HC | SUIT | moonshine
User avatar
nevon
Commander of the Circuloids
Posts: 938
Joined: Thu Feb 14, 2008 8:25 pm
Location: Stockholm, Sweden
Contact:

Re: Splines!

Post by nevon »

I think I broke it...

Image
User avatar
vrld
Party member
Posts: 917
Joined: Sun Apr 04, 2010 9:14 pm
Location: Germany
Contact:

Re: Splines!

Post by vrld »

This happens when you set the smoothness (=subdivision depth) too high. This is also why you shouldn't use Bezier:draw(k).
I have come here to chew bubblegum and kick ass... and I'm all out of bubblegum.

hump | HC | SUIT | moonshine
User avatar
Deecodeuh
Citizen
Posts: 70
Joined: Tue Dec 15, 2009 3:18 am
Location: Michigan, USA

Re: Splines!

Post by Deecodeuh »

The math behind this kind of stuff.. I couldn't take it. ;) Congrats, you're a much better mathematician than I am.
User avatar
vrld
Party member
Posts: 917
Joined: Sun Apr 04, 2010 9:14 pm
Location: Germany
Contact:

Re: Splines!

Post by vrld »

So, I've added BSplines, but did not finish interpolation yet (well, I had them interpolate points, but only in funny ways).
Demo is attached. You can switch between B-Spline and Bézier curve by pressing m. New is dragging (right mouse button).

B-Splines are - other than Bézier curves - not only defined by a control polygon, but also by "knots". These knots define the parameter range of the curve. Every curve segment is influenced by a finite number of knots and control points (other than the Bézier curve, where each control point influences the whole curve. Try pressing [m] in the demo). How exactly is not important right now.

The B-Spline api as is:

BSpline.new(controlpoints, knots)
Creates a new B-Spline curve with control-net given with controlpoints.
knots has to be an ordered array of real values. The number of knots and control points determine the degree of the spline: degree = #knots - #controlpoints + 1, so if you want a cubic (degree = 3) B-Spline and have 4 control points, then you will have to provide 6 knots. If you choose the first and last degree to be the same value, the curve will start in the first and end in the last control point.
You can also omit knots, then a (up to) cubic B-Spline with a knot-distance of one will be created. This is equivalent:

Code: Select all

s1 = BSpline.new({10,400, 100,100, 400,90, 490,380, 530,200}, {0,0,0,1,2,2,2})
s2 = BSpline.new{10,400, 100,100, 400,90, 490,380, 530,200}
BSpline:clone()
Returns a copy of the B-Spline.

BSpline:translate(x,y)
Moves the control-net to pos + (x,y)

BSpline:controlPolygon(min,max)
Returns the control points from min to max. If min and max are omitted, they default to min = 1, max = all.
Same as with Bezier:controlPolygon().

BSpline:knotIndex(t)
Returns the index of the knot corresponding to the parameter t. This is used internally and probably not of much use otherwise.

BSpline:knotMin()
Minimal knot for which the curve is defined.

BSpline:knotMax()
Maximal knot for which the curve is defined.

BSpline:eval(t)
Evaluate the curve with parameter t. If t < knotMin(), then it will be set to knotMin(). If t > knotMax(), then it will be set to knotMax().
You can use this to move an object along a B-Spline:

Code: Select all

p = s:eval(t)
myActor:setPos(p.x, p.y)
BSpline:insertKnot(t)
Inserts a new knot t into the knot sequence without changing the curve. This is used to subdivide/draw the curve, but can also
be used to transform the B-Spline to a Bezier-curve: Every knot needs to be in the sequence degree times.

BSpline:insertKnots(k)
Insert an array of knots.
Example:

Code: Select all

s:insertKnots{1,1,3,2}[/i]

[b]BSpline:subdivide()[/b]
Subdivides the control net. Successive subdivisions will let the control-net converge towards the curve.

[b]BSpline:polygon(k)[/b]
Returns an approximation to the curve with smoothness (= subdivision steps) k.
Use it as [i]Bezier:polygon(k)[/i].

[b]BSpline:draw(k)[/b]
Draws the B-Spline with smoothness k. Don't do this with a high combination of k and control points. Use BSpline:polygon(k) to cache the curve instead.


EDIT: Reupload
Attachments
splines.love
(5.01 KiB) Downloaded 708 times
I have come here to chew bubblegum and kick ass... and I'm all out of bubblegum.

hump | HC | SUIT | moonshine
User avatar
bitlord
Prole
Posts: 10
Joined: Thu Jun 02, 2011 7:06 pm

Re: Splines!

Post by bitlord »

User avatar
slime
Solid Snayke
Posts: 3166
Joined: Mon Aug 23, 2010 6:45 am
Location: Nova Scotia, Canada
Contact:

Re: Splines!

Post by slime »

Wow, this is awesome! Great job vrld. :D
User avatar
cattail
Citizen
Posts: 56
Joined: Mon Feb 13, 2012 4:11 pm

Re: Splines!

Post by cattail »

Awesome! vrld you are my hero.

I dig the hole forum (about 1/3 now) try to find out a "cuver drawing demo" , this is almost what I want .
And if not lookat ths topic, maybe after weeks I'll write a one from a lua forum spline lua file ,
and don't know I have (or not) a skill for it.
User avatar
Faren
Prole
Posts: 17
Joined: Sun Mar 03, 2013 6:33 pm

Re: Splines!

Post by Faren »

Wow, I've been looking for something like this for days, Kudos OP.

Shouldn't the script be in the wiki?
User avatar
Taehl
Dreaming in associative arrays
Posts: 1025
Joined: Mon Jan 11, 2010 5:07 am
Location: CA, USA
Contact:

Re: Splines!

Post by Taehl »

Any plans to add Catmull-Rom splines? I've read that they're useful for all sorts of things.
Earliest Love2D supporter who can't Love anymore. Let me disable pixel shaders if I don't use them, dammit!
Lenovo Thinkpad X60 Tablet, built like a tank. But not fancy enough for Love2D 0.10.0+.
Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot], Google [Bot] and 4 guests