points = nil function getPoints() return points end function init(points_) points = points_ pointDistances = {} local distAd2Sum = 0 local lastP = nil for pointIdx, p in ipairs(points) do if lastP ~= nil then local distAd2 = lastP:distAd2(p) pointDistances[pointIdx-1] = distAd2 distAd2Sum = distAd2Sum + distAd2 end lastP = p end for pointIdx, distAd2 in ipairs(pointDistances) do pointDistances[pointIdx] = distAd2 / distAd2Sum end end function eval(t) if points == nil or #points == 0 then return nil end -- find the closest points for the given t parameter local pointIdx = 1 while pointIdx <= #pointDistances and t - pointDistances[pointIdx] >= 0 do t = t - pointDistances[pointIdx] pointIdx = pointIdx + 1 end if pointIdx == #pointDistances + 1 then return points[pointIdx] end -- normalize the t parameter to only mean the distance between the two closest points t = t / pointDistances[pointIdx] return zigzagInterpolate(points[pointIdx], points[pointIdx+1], t) end function zigzagInterpolate(p1, p2, t) local dx, dy = p2:getX()-p1:getX(), p2:getY()-p1:getY() local dist = math.sqrt(dx*dx + dy*dy) dx, dy = -dy/dist*20, dx/dist*20 local x, y = (p1:getX()+p2:getX())/2, (p1:getY()+p2:getY())/2 local middlePoint = point.new(x+dx, y+dy) if t < 0.5 then return p1:interpolate(middlePoint, t/0.5) else return p1:interpolate(p2, t) end end