local regions = nil
local graph_region = nil
+local GRAPH_FONT, SIDEBAR_FONT
+
function love.load()
GRAPH_FONT = love.graphics.setNewFont(16)
+ SIDEBAR_FONT = love.graphics.setNewFont(24)
graph = Graph:new()
-- other properties
selectedNode = nil;
postDrawFunction = nil;
+ clickNodeFunction = nil;
isMouseDown = false;
update = function(self) end;
local d = (x - nx) * (x - nx) + (y - ny) * (y - ny)
if d <= 20 * 20 then
- self.selectedNode = node.id
+ if self.clickNodeFunction == nil then
+ self.selectedNode = node.id
+ else
+ self.clickNodeFunction(node)
+ end
end
end
end;
+
mouseup = function(self, x, y)
self.isMouseDown = false
end;
graph:setNodePos(self.selectedNode, x, y)
end
end;
- mouseenter = function(self)
- end;
+
+ mouseenter = function(self) end;
+
mouseleave = function(self)
self.isMouseDown = false
end;
regions:add(graph_region)
+ regions:add {
+ priority = 1;
+ rect = { 0, 0, 200, 600 };
+
+ buttons = {
+ {
+ text = "Add node",
+ click = function()
+ graph:addNode(300, 300)
+ end;
+ };
+ {
+ text = "Delete node",
+ click = function()
+ graph:deleteNode(graph_region.selectedNode)
+ end;
+ };
+ {
+ text = "Add arc",
+ click = function()
+ local curr = graph_region.selectedNode
+ if curr == nil then return end
+
+ graph_region.clickNodeFunction = function(node)
+ graph:addArc(curr, node.id, 1)
+ graph_region.clickNodeFunction = nil
+ end
+ end;
+ };
+ {
+ text = "Add edge",
+ click = function()
+ local curr = graph_region.selectedNode
+ if curr == nil then return end
+
+ graph_region.clickNodeFunction = function(node)
+ graph:addEdge(curr, node.id, 1)
+ graph_region.clickNodeFunction = nil
+ end
+ end;
+ };
+ {
+ text = "Run Dijkstras",
+ click = function()
+ if graph_region.selectedNode ~= nil then
+ createDijskstraStepper(graph_region.selectedNode)
+ end
+ end;
+ };
+ };
+ mousePos = -1;
+
+ update = function(self) end;
+
+ draw = function(self)
+ love.graphics.setFont(SIDEBAR_FONT)
+ for i, button in ipairs(self.buttons) do
+ if self.mousePos >= (i - 1) * 60 + 10 and self.mousePos <= i * 60 + 10 then
+ love.graphics.setColor(.4, .4, .4)
+ else
+ love.graphics.setColor(.2, .2, .2)
+ end
+ love.graphics.rectangle("fill", 10, (i - 1) * 60 + 10, 180, 40)
+
+ love.graphics.setColor(1, 1, 1)
+ love.graphics.printf(button.text, 0, (i - 1) * 60 + 15, 200, "center")
+ end
+ end;
+
+ mousedown = function(self, x, y)
+ for i, button in ipairs(self.buttons) do
+ if y >= (i - 1) * 60 + 10 and y <= i * 60 + 10 then
+ button.click()
+ end
+ end
+ end;
+ mouseup = function(self, x, y) end;
+ mousemove = function(self, x, y, dx, dy)
+ self.mousePos = y
+ end;
+ mouseenter = function(self) end;
+ mouseleave = function(self)
+ self.mousePos = -1
+ end;
+ }
-- regions:add {
-- priority = 0;
-- }
end
-function createDijskstraStepper()
+local dijkstrasOpen = false
+function createDijskstraStepper(start)
+ if dijkstrasOpen then return end
+
+ dijkstrasOpen = true
local step = -1
+ local isDone = false
function updateDijkstras()
- local dj = graph:dijkstras(0, step)
+ local dj, done = graph:dijkstras(start, step)
+ isDone = done
graph_region.postDrawFunction = function(reg)
drawDijkstras(graph, dj)
end
mousedown = function(self, x, y)
if x >= 265 and x <= 295 then
step = step - 1
+ isDone = false
if step < -1 then step = -1 end
elseif x >= 305 and x <= 335 then
- step = step + 1
+ if not isDone then
+ step = step + 1
+ end
end
updateDijkstras()
if x >= 550 then
regions:remove(reg_id)
graph_region.postDrawFunction = nil
+ dijkstrasOpen = false
end
end;
mouseup = function(self, x, y) end;
-- DRAWING FUNCTIONS
+function drawEdge(x1, y1, x2, y2, directed, weight, color)
+ love.graphics.setColor(color)
+
+ love.graphics.line(x1, y1, x2, y2)
+
+ local cx = math.lerp(x1, x2, 0.5)
+ local cy = math.lerp(y1, y2, 0.5)
+ local arrowSize = 22
+
+ if directed == 2 then
+ local alpha = math.atan2(x2 - x1, y2 - y1)
+
+ local triangle = {
+ cx + arrowSize * math.sin(alpha + 0 * math.pi / 3), cy + arrowSize * math.cos(alpha + 0 * math.pi / 3),
+ cx + arrowSize * math.sin(alpha + 2 * math.pi / 3), cy + arrowSize * math.cos(alpha + 2 * math.pi / 3),
+ cx + arrowSize * math.sin(alpha + 4 * math.pi / 3), cy + arrowSize * math.cos(alpha + 4 * math.pi / 3)
+ }
+
+ love.graphics.polygon("fill", triangle)
+ elseif directed == 1 then
+ love.graphics.rectangle("fill", cx - arrowSize * .6, cy - arrowSize * .6, arrowSize * 1.2, arrowSize * 1.2)
+ end
+
+ love.graphics.setColor(1, 1, 1)
+ love.graphics.printf(tostring(weight), cx - 20, cy - 10, 40, "center")
+end
+
local NODE_INNER_RADIUS = 17
local NODE_OUTER_RADIUS = 20
function drawGraph(graph, selectedNode)
local nodes = graph:getNodes()
local edges = graph:getEdges()
+ love.graphics.setFont(GRAPH_FONT)
love.graphics.setLineWidth(4)
for _, edge in pairs(edges) do
- love.graphics.setColor(0, 0, 0)
local x1 = nodes[edge.from_node].x
local y1 = nodes[edge.from_node].y
local x2 = nodes[edge.to_node].x
local y2 = nodes[edge.to_node].y
- love.graphics.line(x1, y1, x2, y2)
-
- local cx = math.lerp(x1, x2, 0.5)
- local cy = math.lerp(y1, y2, 0.5)
- local arrowSize = 22
-
- if edge.directed then
- local alpha = math.atan2(x2 - x1, y2 - y1)
-
- local triangle = {
- cx + arrowSize * math.sin(alpha + 0 * math.pi / 3), cy + arrowSize * math.cos(alpha + 0 * math.pi / 3),
- cx + arrowSize * math.sin(alpha + 2 * math.pi / 3), cy + arrowSize * math.cos(alpha + 2 * math.pi / 3),
- cx + arrowSize * math.sin(alpha + 4 * math.pi / 3), cy + arrowSize * math.cos(alpha + 4 * math.pi / 3)
- }
-
- love.graphics.polygon("fill", triangle)
- else
- love.graphics.rectangle("fill", cx - arrowSize * .6, cy - arrowSize * .6, arrowSize * 1.2, arrowSize * 1.2)
- end
- love.graphics.setColor(1, 1, 1)
- love.graphics.printf(tostring(edge.weight), cx - 20, cy - 10, 40, "center")
+ drawEdge(x1, y1, x2, y2, (edge.directed and 2 or 1), edge.weight, {0, 0, 0})
end
for _, node in pairs(nodes) do
function drawDijkstras(graph, dijkstras)
love.graphics.setFont(GRAPH_FONT)
+ if dijkstras.from >= 0 and dijkstras.to >= 0 then
+ local x1, y1 = graph:getNodePos(dijkstras.from)
+ local x2, y2 = graph:getNodePos(dijkstras.to)
+
+ drawEdge(x1, y1, x2, y2, 0, dijkstras.weight, {1, 0, 0})
+ end
+
for _, node in ipairs(dijkstras) do
if node.distance >= 0 then
local x, y = graph:getNodePos(node.id)
- love.graphics.setColor(0, 1, 0)
+ love.graphics.setColor(1, 0, 0)
love.graphics.circle("fill", x, y, NODE_INNER_RADIUS)
love.graphics.setColor(0, 0, 0)