Catmull-Rom Spline Rendering Function (curves)
Posted: Wed Mar 10, 2010 6:48 am
Alrighty LOVE community, here's something to play with. It's a single function that takes a table of point values as an input and draws a nice curve, which is technically a Catmull-Rom Spline. As such it's a function you'll want to use in your draw loop. Although I did my best to make it optimized while preserving readability and utility, I'm sure there are still optimizations that could be done... which I'd be happy to hear about.
Features:
-Curves correctly pass through every point in the specified table.
-Detail is a parameter. Try changing the curve detail with time or mouse position!
-Detail automatically scales down in places that aren't very curvy, so there are isn't any time wasted on drawing a bunch of parallel lines instead of one.
-Takes a line drawing function as a parameter, meaning that ANYTHING can be drawn in a spline-fashion. (see the example .love file)
The function code:
There is an example .love attached as well. Check it out to see how the func parameter works.
Controls: Left click a couple times.
Features:
-Curves correctly pass through every point in the specified table.
-Detail is a parameter. Try changing the curve detail with time or mouse position!
-Detail automatically scales down in places that aren't very curvy, so there are isn't any time wasted on drawing a bunch of parallel lines instead of one.
-Takes a line drawing function as a parameter, meaning that ANYTHING can be drawn in a spline-fashion. (see the example .love file)
The function code:
Code: Select all
function RenderSpline(tab, detail, func) --takes a table in the form [x1, y1, x2, y2, etc.]
if(tab and (#tab >= 4)) then
local Points = {}
for i=1, (#tab-2), 2 do
local p1x = tab[i]
local p1y = tab[i+1]
local p2x = tab[i+2]
local p2y = tab[i+3]
local p0x = tab[i-2]
local p0y = tab[i-1]
local p3x = tab[i+4]
local p3y = tab[i+5]
--Create a colinearity function to test how colinear three points are:
local colinearity = 0
local function GetColinearity(x1, y1, x2, y2, x3, y3)
local ux = x2 - x1
local uy = y2 - y1
local vx = x3 - x2
local vy = y3 - y2
local udv = (ux*vx + uy*vy)
local udu = (ux*ux + uy*uy)
local vdv = (vx*vx + vy*vy)
local scalar = 1
if(udv < 0) then --the angle is greater than 90 degrees.
scalar = 0
end
return scalar * ((udv*udv) / (udu*vdv))
end
--Calculate the colinearity and the control points for the section:
local t1x = 0
local t1y = 0
local colin1 = 0
if(p0x and p0y) then
t1x = 0.5 * (p2x - p0x)
t1y = 0.5 * (p2y - p0y)
colin1 = GetColinearity(p0x, p0y, p1x, p1y, p2x, p2y)
else
colin1 = nil
end
local t2x = 0
local t2y = 0
local colin2 = 0
if(p3x and p3y) then
t2x = 0.5 * (p3x - p1x)
t2y = 0.5 * (p3y - p1y)
colin2 = GetColinearity(p1x, p1y, p2x, p2y, p3x, p3y)
else
colin2 = nil
end
if(colin1 and colin2) then
colinearity = ((colin1+colin2)/2)
elseif(colin1) then
colinearity = colin1
elseif(colin2) then
colinearity = colin2
else
colinearity = 0
end
--Get the proper detail using the computed colinearity, then calculate the spline points:
local rdetail = (detail * (1-colinearity))
for j=0, rdetail do
local s = j/rdetail
local s2 = s*s
local s3 = s*s*s
local h1 = 2*s3 - 3*s2 + 1
local h2 = -2*s3 + 3*s2
local h3 = s3 - 2*s2 + s
local h4 = s3 - s2
local px = (h1*p1x) + (h2*p2x) + (h3*t1x) + (h4*t2x)
local py = (h1*p1y) + (h2*p2y) + (h3*t1y) + (h4*t2y)
table.insert(Points, px)
table.insert(Points, py)
end
if(math.ceil(rdetail) > rdetail) then
table.insert(Points, p2x)
table.insert(Points, p2y)
end
end
func(Points) --Draws the spline using the function specified.
end
end
Controls: Left click a couple times.