init: tool for graphing functions and slope fields in love2d
This commit is contained in:
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"runtime.version": "LuaJIT",
|
||||||
|
"workspace.library": ["../love2d"],
|
||||||
|
"runtime.special": {
|
||||||
|
"love.filesystem.load": "loadfile"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
local function getPixelPosition(point, minPoint, maxPoint, drawBounds)
|
||||||
|
if
|
||||||
|
point[1] < minPoint[1]
|
||||||
|
or point[1] > maxPoint[1]
|
||||||
|
or point[2] < minPoint[2]
|
||||||
|
or point[2] > maxPoint[2]
|
||||||
|
then
|
||||||
|
error("Point ("..point[1]..", "..point[2]..") outside the bounds ("
|
||||||
|
..minPoint[1]..", "..minPoint[2]..") to ("..maxPoint[1]..", "..maxPoint[2]..")")
|
||||||
|
end
|
||||||
|
local pointBound = {maxPoint[1] - minPoint[1], maxPoint[2] - minPoint[2]}
|
||||||
|
local pointOffset = {point[1] - minPoint[1], -point[2] - minPoint[2]}
|
||||||
|
local position = {
|
||||||
|
(pointOffset[1] / pointBound[1]) * drawBounds.width + drawBounds.x,
|
||||||
|
(pointOffset[2] / pointBound[2]) * drawBounds.height + drawBounds.y
|
||||||
|
}
|
||||||
|
return position[1], position[2]
|
||||||
|
end
|
||||||
|
|
||||||
|
function GraphFunction(x, y, width, height, func)
|
||||||
|
local points = {}
|
||||||
|
local origin = {x = (width + x) / 2, y = (height + y) / 2}
|
||||||
|
local neg_x, neg_y = -math.floor(origin.x), -math.floor(origin.y)
|
||||||
|
local pos_x, pos_y = math.floor(origin.x), math.floor(origin.y)
|
||||||
|
for i = neg_x, pos_x, 1 do
|
||||||
|
local j = math.floor(func(i))
|
||||||
|
if j > neg_y and j < pos_y then
|
||||||
|
local k, l = getPixelPosition({i,j}, {neg_x,neg_y}, {pos_x,pos_y},
|
||||||
|
{x=x,y=x,width=width,height=height})
|
||||||
|
table.insert(points, k)
|
||||||
|
table.insert(points, l)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return points
|
||||||
|
end
|
||||||
|
|
||||||
|
function GetLineFromSlope(midpoint, slope, length, color)
|
||||||
|
color = color or {1, 1, 1}
|
||||||
|
local delta_x, delta_y
|
||||||
|
if slope == nil then
|
||||||
|
delta_x, delta_y = 0, length
|
||||||
|
else
|
||||||
|
delta_x = math.sqrt((length ^ 2) / (1 + slope ^ 2))
|
||||||
|
delta_y = -(slope * delta_x)
|
||||||
|
end
|
||||||
|
local x1 = midpoint.x - delta_x / 2
|
||||||
|
local y1 = midpoint.y - delta_y / 2
|
||||||
|
local x2 = x1 + delta_x
|
||||||
|
local y2 = y1 + delta_y
|
||||||
|
return {
|
||||||
|
p1 = {x = x1, y = y1},
|
||||||
|
p2 = {x = x2, y = y2},
|
||||||
|
midpoint = midpoint,
|
||||||
|
color = color
|
||||||
|
}
|
||||||
|
end
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
local function factorial(n)
|
||||||
|
if n <= 2 then
|
||||||
|
return n
|
||||||
|
end
|
||||||
|
return n * factorial(n-1)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function calculate_e(terms)
|
||||||
|
local e = 1
|
||||||
|
for i = 1, terms do
|
||||||
|
e = e + 1 / factorial(i)
|
||||||
|
end
|
||||||
|
return e
|
||||||
|
end
|
||||||
|
return calculate_e(10)
|
||||||
@@ -0,0 +1,165 @@
|
|||||||
|
local utf8 = require("utf8")
|
||||||
|
|
||||||
|
require("coordinates")
|
||||||
|
-- to use with functions involving e
|
||||||
|
--local e = require("eulerNumber")
|
||||||
|
|
||||||
|
local function differential(x, y)
|
||||||
|
return 2*y
|
||||||
|
end
|
||||||
|
|
||||||
|
local function loadWindow()
|
||||||
|
love.window.setTitle("Slope Fields")
|
||||||
|
love.keyboard.setKeyRepeat(true)
|
||||||
|
end
|
||||||
|
love.load = loadWindow
|
||||||
|
|
||||||
|
local function drawLine(line)
|
||||||
|
love.graphics.setColor(unpack(line.color))
|
||||||
|
love.graphics.line(line.p1.x, line.p1.y, line.p2.x, line.p2.y)
|
||||||
|
love.graphics.circle("fill", line.midpoint.x, line.midpoint.y, 4)
|
||||||
|
end
|
||||||
|
|
||||||
|
local width, height = love.window.getMode()
|
||||||
|
|
||||||
|
local boxMargin = 10
|
||||||
|
local boxHeight = math.max(height / 12, 20)
|
||||||
|
local textbox = {
|
||||||
|
x = boxMargin,
|
||||||
|
y = height - (boxHeight + boxMargin),
|
||||||
|
width = width - 2 * boxMargin,
|
||||||
|
height = boxHeight,
|
||||||
|
padding = 5,
|
||||||
|
text = 'x',
|
||||||
|
active = false,
|
||||||
|
colors = {
|
||||||
|
background = {0.2, 0.2, 0.2},
|
||||||
|
text = {0.9, 0.9, 0.9}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
local graphbox = {
|
||||||
|
x = boxMargin,
|
||||||
|
y = boxMargin,
|
||||||
|
width = width - 2 * boxMargin,
|
||||||
|
height = textbox.y - 2 * boxMargin,
|
||||||
|
colors = {
|
||||||
|
background = {0.2, 0.2, 0.2}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
local center = {
|
||||||
|
x = graphbox.x + graphbox.width / 2,
|
||||||
|
y = graphbox.y + graphbox.height / 2
|
||||||
|
}
|
||||||
|
local scale = 5
|
||||||
|
local xScale, yScale
|
||||||
|
local step
|
||||||
|
if graphbox.width <= graphbox.height then
|
||||||
|
step = graphbox.width / (2 * (scale+1))
|
||||||
|
xScale = scale
|
||||||
|
yScale = math.floor(graphbox.height / (2 * step)) - 1
|
||||||
|
else
|
||||||
|
step = graphbox.height / (2 * (scale+1))
|
||||||
|
yScale = scale
|
||||||
|
xScale = math.floor(graphbox.width / (2 * step)) - 1
|
||||||
|
end
|
||||||
|
|
||||||
|
local lines = {
|
||||||
|
grid = {},
|
||||||
|
axes = {
|
||||||
|
x = GetLineFromSlope(center, 0, graphbox.width),
|
||||||
|
y = GetLineFromSlope(center, nil, graphbox.height)
|
||||||
|
},
|
||||||
|
field = {}
|
||||||
|
}
|
||||||
|
local xpos, ypos = graphbox.x, graphbox.y + graphbox.height
|
||||||
|
for y = -yScale, yScale, 1 do
|
||||||
|
ypos = ypos - step
|
||||||
|
lines.grid[{y=y}] = GetLineFromSlope({x = center.x, y = ypos}, 0, graphbox.width, {0.3, 0.3, 0.3})
|
||||||
|
end
|
||||||
|
for x = -xScale, xScale, 1 do
|
||||||
|
xpos = xpos + step
|
||||||
|
lines.grid[{x=x}] = GetLineFromSlope({x = xpos, y = center.y}, nil, graphbox.height, {0.3, 0.3, 0.3})
|
||||||
|
ypos = graphbox.y + graphbox.height
|
||||||
|
for y = -yScale, yScale, 1 do
|
||||||
|
ypos = ypos - step
|
||||||
|
lines.field[{x, y}] = GetLineFromSlope({x = xpos, y = ypos}, differential(x,y), 50, {0, 0.5, 1})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function func(x)
|
||||||
|
return x^2
|
||||||
|
end
|
||||||
|
local points = GraphFunction(graphbox.x, graphbox.y, graphbox.width, graphbox.height, func)
|
||||||
|
|
||||||
|
local function drawScene()
|
||||||
|
love.graphics.setColor(unpack(graphbox.colors.background))
|
||||||
|
love.graphics.rectangle('fill',
|
||||||
|
graphbox.x, graphbox.y,
|
||||||
|
graphbox.width, graphbox.height,
|
||||||
|
4, 4)
|
||||||
|
|
||||||
|
love.graphics.setColor(unpack(textbox.colors.background))
|
||||||
|
love.graphics.rectangle('fill',
|
||||||
|
textbox.x, textbox.y,
|
||||||
|
textbox.width, textbox.height,
|
||||||
|
4, 4)
|
||||||
|
|
||||||
|
love.graphics.setColor(unpack(textbox.colors.text))
|
||||||
|
love.graphics.printf(textbox.text,
|
||||||
|
textbox.x + textbox.padding, textbox.y + textbox.padding,
|
||||||
|
textbox.width, 'left', 0, 2, 2)
|
||||||
|
|
||||||
|
for _, line in pairs(lines.grid) do
|
||||||
|
drawLine(line)
|
||||||
|
end
|
||||||
|
for _, line in pairs(lines.axes) do
|
||||||
|
drawLine(line)
|
||||||
|
end
|
||||||
|
for _, line in pairs(lines.field) do
|
||||||
|
drawLine(line)
|
||||||
|
end
|
||||||
|
|
||||||
|
if points ~= nil then
|
||||||
|
love.graphics.setColor(0,1,0)
|
||||||
|
love.graphics.points(points)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
love.draw = drawScene
|
||||||
|
|
||||||
|
local function textboxinput(text)
|
||||||
|
if textbox.active and string.match(text,"[xy+%-%/*%^%d()]") then
|
||||||
|
textbox.text = textbox.text .. text
|
||||||
|
end
|
||||||
|
end
|
||||||
|
love.textinput = textboxinput
|
||||||
|
|
||||||
|
local function keypress(key)
|
||||||
|
if key == "backspace" then
|
||||||
|
local byteoffset = utf8.offset(textbox.text, -1)
|
||||||
|
|
||||||
|
if byteoffset then
|
||||||
|
textbox.text = string.sub(textbox.text, 1, byteoffset - 1)
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if key == "return" then
|
||||||
|
textbox.active = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
love.keypressed = keypress
|
||||||
|
|
||||||
|
local function mousepress(x, y)
|
||||||
|
if
|
||||||
|
x >= textbox.x and
|
||||||
|
x <= textbox.x + textbox.width and
|
||||||
|
y >= textbox.y and
|
||||||
|
y <= textbox.y + textbox.height
|
||||||
|
then
|
||||||
|
textbox.active = true
|
||||||
|
elseif textbox.active then
|
||||||
|
textbox.active = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
love.mousepressed = mousepress
|
||||||
|
|
||||||
Reference in New Issue
Block a user