This article is the first part of a two part tutorial to do curve fitting. The motivation to do this came when I was playing the Flight Control Center game on my IPhone. I was very interested in this kind of game and wanted to know how to build a game like that. I wrote a sample on Corona SDK but the result was not as I expected. I found the airplane oscillated like a doll 🙂 Soon, I recognized the reason: because the path I had made was not smooth. Moreover, I recognized that to draw a smooth curve on a touched screen is almost impossible. So my mission was quite clear: “drawing a smooth curve that approximately like the curve made”.
I looked on the Internet for the solution and came up with the combination of 2 algorithms for curve fitting that solve the issue beautifully. Basically, there are two steps to be implemented:
– First, reduce the points of the handmade curve by approximating it using the algorithm of Ramer-Douglas-Peucker. This article is all about the implementation of this on LUA language for Corona SDK. I won’t write too much about the algorithm’s explanation as it was done greatly in the wiki.
– Second, draw a continuous curve through the received points in step 1 using the algorithm of P.J.Schneider. The implementation of this is also on Corona and comes on the next post.
Let’s have a look on the pseudo code provided from the wiki:

The PerpendicularDistance mentioned in the pseudo code is the distance from a point to a line that is measured by the length of the line that perpendicularly connects that point to the line. It is more explained by the below figure:
The LUA code for calculating perpendicular distance:

Here’s the code for implementing the main algorithm, please refer to the above pseudo code

-- points are the set of points to be reduced
-- tolerance is value indicates degree of correctness for approximation
-- the other parameters are for recursion
function douglaspeucker(points, firstpoint, lastpoint, tolerance, pointIndices)
local maxD = 0
local indexFurthest = 0
for i = firstpoint, lastpoint do
local distance = dPointLine(points[i], points[firstpoint], points[lastpoint])
if distance > maxD then
maxD = distance
indexFurthest = i
end
end
if maxD > tolerance and indexFurthest ~= 1 then
table.insert(pointIndices, indexFurthest)
douglaspeucker(points, firstpoint, indexFurthest, tolerance, pointIndices)
douglaspeucker(points, indexFurthest, lastpoint, tolerance, pointIndices)
end
end