Page 2 of 2
Re: Splines!
Posted: Mon Mar 04, 2013 3:49 am
by Ref
For CatMullRom spline all you need is:
Code: Select all
function smooth( points, steps )
if #points < 3 then return points end
local steps = steps or 5
local spline = {}
local count = #points - 1
local p0, p1, p2, p3, x, y
for i = 1, count do
if i == 1 then
p0, p1, p2, p3 = points[i], points[i], points[i + 1], points[i + 2]
elseif
i == count then
p0, p1, p2, p3 = points[#points - 2], points[#points - 1], points[#points], points[#points]
else
p0, p1, p2, p3 = points[i - 1], points[i], points[i + 1], points[i + 2]
end
for t = 0, 1, 1 / steps do
x = 0.5*((2*p1.x)+(p2.x-p0.x)*t+(2*p0.x-5*p1.x+4*p2.x-p3.x)*t*t+(3*p1.x-p0.x-3*p2.x+p3.x)*t*t*t)
y = 0.5*((2*p1.y)+(p2.y-p0.y)*t+(2*p0.y-5*p1.y+4*p2.y-p3.y)*t*t+(3*p1.y-p0.y-3*p2.y+p3.y )*t*t*t)
--prevent duplicate entries
if not(#spline > 0 and spline[#spline].x == x and spline[#spline].y == y) then
table.insert( spline , { x = x , y = y } ) -- table of indexed points
end
end
end
return spline
end
where points are the points you want the curve to go through and steps is the number of point to interpolate between.
Re: Splines!
Posted: Mon Mar 04, 2013 7:47 am
by Taehl
So they only way to have a spline is in discrete steps? You can't just ask it for an arbitrary "position in the spline" (maybe a percentage or something) and get one point?
Re: Splines!
Posted: Mon Mar 04, 2013 2:46 pm
by Ref
Anything's possible, if you’re devious enough.
Just requires a little coding and at least four points into the spline.
Edit:
Just put something together that I think simulates what you want.
FPS not too bad.
Be warned that there is a problem with what happens at the end of the spline - needs some more head scratching.
Re: Splines!
Posted: Tue Mar 05, 2013 11:32 pm
by MarekkPie
I actually had to implement arbitrary splines are any degree for a graphics class this semester. I believe the method Ref is describing will only give you cubic Catmull-Rom splines. Granted, that's what most people use, but if you want something a bit more robust, here is some Lua code. I quickly converted my C++ code for the project to Lua, so there may be some mistakes, but hopefully the general idea is there:
Code: Select all
local CatmullRom = {}
CatmullRom.__index = CatmullRom
-- http://en.wikipedia.org/wiki/De_Boor%27s_algorithm
local function deBoor(time, values, degree, sep, start)
start = start or 1
local newValues = {}
for i = 0, #values - 1 do
local lhs = (start + i + sep - time) / sep * values[i + 1]
local rhs = (time - (start + i)) / sep * values[i + 2]
table.insert(newValues, lhs + rhs)
end
if sep == 1 then
if #newValues == 1 then
return newValues[0]
else
local i = math.floor(time - degree)
return newValues[i < #newValues and i or i - 1]
end
else
return deBoor(time, newValues, sep - 1, start + 1)
end
end
-- http://en.wikipedia.org/wiki/Neville_algorithm
local function neville(time, values, degree, sep)
sep = sep or 1
local newValues = {}
for i = 0, #values - 1 do
local lhs = (i + sep - time) / sep * values[i + 1]
local rhs = (time - i) / sep * values[i + 2]
table.insert(newValues, lhs + rhs)
end
if sep == degree + 1 then
return deBoor(time, newValues, degree, sep - 1)
else
return neville(time, newValues, degree, sep + 1)
end
end
function CatmullRom:new(controlPoints, degree)
return setmetatable({
controlPoints = controlPoints,
degree = degree,
interpolants = {},
}, self)
end
function CatmullRom:initialize()
for i = self.degree, #controlPoints - degree, 0.1 do
table.insert(self.interpolants, self:interpolate(i))
end
end
-- Gets an arbitrary point of the Catmull-Rom spline
function CatmullRom:interpolate(time)
-- Separate the x- and y-coordinates of the points
local x, y = {}, {}
for _,v in ipairs(self.controlPoints) do
table.insert(x, v[0])
table.insert(y, v[1])
end
-- Catmull-Rom splines are a combination of Lagrange curves and B-Splines,
-- so we use Neville's algorithm to build the Lagrange steps
-- and deBoor's algorithm to build the B-Spline steps
return { neville(time, x, self.degree), neville(time, y, self.degree) }
end
function CatmullRom:draw()
love.graphics.line(self.interpolants)
end
return setmetatable(CatmullRom, { __call = CatmullRom.new })
Re: Splines!
Posted: Wed Mar 06, 2013 3:42 pm
by Ref
Would really appreciate a Love demo so that we can see the difference 'degree' makes.
Not obvious as to the feeding and care required by your library (at least for the mentally challenged.)
Didn't mean to imply that the cubic CatMullRom I posted first was unstable (it isn't!) only that my hack job to get % along curve didn't handle the last control point properly (a common problem with curve fitting).
Re: Splines!
Posted: Wed Mar 06, 2013 10:41 pm
by MarekkPie
I'll try and make a similar library to what vrld has over Spring Break (which is next week for my school). To the human eye, there isn't much difference between the continuity (smoothness) a cubic Catmull-Rom spline provides and higher degree Catmull-Rom splines, but when you start getting into shading and reflections on Catmull-Rom surfaces, higher order smoothness becomes a factor (since there is some derivation of the curve going on in those calculations).
I'm really just regurgitating what my professor has talked about this semester. If you'd like to read the notes yourself, they're freely available online at
his course website.