Module:CurveTable

local p = {}

-- Parses a string of the format `x,y` with numerical `x` and `y` into an array with named numbers `x` and `y`. function parsePoint(string) local stringArray = mw.text.split(string, ",")

local point = {} point["x"] = tonumber(stringArray[1]) point["y"] = tonumber(stringArray[2])

return point end

-- Rounds `value` according to the type of rounding indicated by `mode`. function round(mode, value) if mode == "ceil"   then return math.ceil(value) elseif mode == "floor"  then return math.floor(value) elseif mode == "trunc"  then return value >= 0 and math.floor(value - 0.5) or math.ceil(value + 0.5) elseif mode == "nearest" then return math.floor(value + 0.5) else return value end end

-- Interpolates (or extrapolates) the x-coordinate `c` based on points `a` and `b`. function interpolatePoint(a, b, c)   return a["y"] + (c - a["x"]) * (b["y"] - a["y"]) / (b["x"] - a["x"]) end

-- Interpolate (or extrapolates) the x-coordinate `target` in the curve table `curveTable`. function interpolate(curveTable, target) if #curveTable == 1 then -- One point in curve table; interpret as horizontal line return parsePoint(curveTable[1])["y"] end

-- Find the first point that is greater than `target` for i = 1, #curveTable, 1 do       local point = parsePoint(curveTable[i])

if target == point["x"] then -- `target` is on a point in the curve table; no interpolation/extrapolation required return point["y"] elseif target < point["x"] then if i == 1 then -- `target` comes before the first point; extrapolate from first two points in table return interpolatePoint(parsePoint(curveTable[1]), parsePoint(curveTable[2]), target) else -- `target` is in between two points; interpolate between current and previous point return interpolatePoint(parsePoint(curveTable[i - 1]), parsePoint(curveTable[i]), target) end end end

-- `target` is after last point. Extrapolate from last two points in table return interpolatePoint(parsePoint(curveTable[#curveTable - 1]), parsePoint(curveTable[#curveTable]), target) end

-- See documentation at Template:CurveTable. function p.evaluate(frame) local curveTable = mw.text.split(frame.args[1], " ") if #curveTable == 0 then -- Empty curve table return "Not enough points in curve table." end local target1 = tonumber(frame.args[2]) local result1 = round(frame.args["round"], interpolate(curveTable, target1))

if frame.args[3] ~= nil and frame.args[3] ~= "" then local target2 = tonumber(frame.args[3]) local result2 = round(frame.args["round"], interpolate(curveTable, target2))

return result1 .. "-" .. result2 end

return result1 end

return p