mirror of
https://github.com/rm-code/Graphoon.git
synced 2024-11-16 18:24:22 +00:00
Add first working draft of the force directed graph
This commit is contained in:
parent
ff55890510
commit
805278d67a
13
Edge.lua
Normal file
13
Edge.lua
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
local Edge = {};
|
||||||
|
|
||||||
|
function Edge.new( id, origin, target )
|
||||||
|
local self = {};
|
||||||
|
|
||||||
|
self.id = id;
|
||||||
|
self.origin = origin;
|
||||||
|
self.target = target;
|
||||||
|
|
||||||
|
return self;
|
||||||
|
end
|
||||||
|
|
||||||
|
return Edge;
|
78
Graph.lua
Normal file
78
Graph.lua
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
local Node = require('Node');
|
||||||
|
local Edge = require('Edge');
|
||||||
|
|
||||||
|
local Graph = {};
|
||||||
|
|
||||||
|
-- TODO remove / replace LÖVE functions
|
||||||
|
function Graph.new()
|
||||||
|
local self = {};
|
||||||
|
|
||||||
|
-- Node Objects are stored in a table using their ID as an index.
|
||||||
|
local nodes = {};
|
||||||
|
local edges = {};
|
||||||
|
local edgeIDs = 0;
|
||||||
|
|
||||||
|
local center = Node.new( 'center ', love.graphics.getWidth() * 0.5, love.graphics.getHeight() * 0.5);
|
||||||
|
|
||||||
|
function self:init( table )
|
||||||
|
math.randomseed(120123091239581834213143141);
|
||||||
|
|
||||||
|
for _, id in pairs( table.nodes ) do
|
||||||
|
self:addNode( Node.new( id, math.random(100, 800), math.random(100, 400) ) );
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, edge in pairs( table.edges ) do
|
||||||
|
self:addEdge( nodes[edge[1]], nodes[edge[2]] );
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function self:addNode( node )
|
||||||
|
nodes[node:getID()] = node;
|
||||||
|
end
|
||||||
|
|
||||||
|
function self:addEdge( origin, target )
|
||||||
|
edges[edgeIDs] = Edge.new( edgeIDs, origin, target );
|
||||||
|
edgeIDs = edgeIDs + 1;
|
||||||
|
end
|
||||||
|
|
||||||
|
function self:update( dt, ... )
|
||||||
|
for _, edge in pairs( edges ) do
|
||||||
|
edge.origin:attractTo( edge.target );
|
||||||
|
edge.target:attractTo( edge.origin );
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, nodeA in pairs( nodes ) do
|
||||||
|
nodeA:attractTo( center );
|
||||||
|
for _, nodeB in pairs( nodes ) do
|
||||||
|
if nodeA ~= nodeB then
|
||||||
|
nodeA:repelFrom( nodeB );
|
||||||
|
end
|
||||||
|
end
|
||||||
|
nodeA:move( dt );
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function self:draw()
|
||||||
|
for _, edge in pairs( edges ) do
|
||||||
|
love.graphics.line( edge.origin:getX(), edge.origin:getY(), edge.target:getX(), edge.target:getY() );
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, nodeA in pairs( nodes ) do
|
||||||
|
love.graphics.points( nodeA:getX(), nodeA:getY() );
|
||||||
|
love.graphics.print( nodeA:getID(), nodeA:getX(), nodeA:getY() );
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function self:getNodeAt(x, y, range)
|
||||||
|
for _, node in pairs( nodes ) do
|
||||||
|
local nx, ny = node:getPosition();
|
||||||
|
if x < nx + range and x > nx - range and y < ny + range and y > ny - range then
|
||||||
|
return node;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return self;
|
||||||
|
end
|
||||||
|
|
||||||
|
return Graph;
|
100
Node.lua
Normal file
100
Node.lua
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
local Node = {};
|
||||||
|
|
||||||
|
local FORCE_SPRING = -0.01;
|
||||||
|
local FORCE_CHARGE = 100000;
|
||||||
|
|
||||||
|
local FORCE_MAX = 4;
|
||||||
|
local NODE_SPEED = 8;
|
||||||
|
local DAMPING_FACTOR = 0.95;
|
||||||
|
|
||||||
|
---
|
||||||
|
-- @param id - A unique id which will be used to reference this node.
|
||||||
|
--
|
||||||
|
function Node.new( id, x, y )
|
||||||
|
local self = {};
|
||||||
|
|
||||||
|
local px, py = x or 0, y or 0;
|
||||||
|
local ax, ay = 0, 0;
|
||||||
|
local vx, vy = 0, 0;
|
||||||
|
|
||||||
|
---
|
||||||
|
-- Clamps a value to a certain range.
|
||||||
|
-- @param min
|
||||||
|
-- @param val
|
||||||
|
-- @param max
|
||||||
|
--
|
||||||
|
local function clamp( min, val, max )
|
||||||
|
return math.max( min, math.min( val, max ) );
|
||||||
|
end
|
||||||
|
|
||||||
|
---
|
||||||
|
-- Calculates the new xy-acceleration for this node.
|
||||||
|
-- The values are clamped to keep the graph from "exploding".
|
||||||
|
-- @param fx - The force to apply in x-direction.
|
||||||
|
-- @param fy - The force to apply in y-direction.
|
||||||
|
--
|
||||||
|
local function applyForce( fx, fy )
|
||||||
|
ax = clamp( -FORCE_MAX, ax + fx, FORCE_MAX );
|
||||||
|
ay = clamp( -FORCE_MAX, ay + fy, FORCE_MAX );
|
||||||
|
end
|
||||||
|
|
||||||
|
function self:attractTo( node )
|
||||||
|
local dx, dy = px - node:getX(), py - node:getY();
|
||||||
|
local distance = math.sqrt(dx * dx + dy * dy);
|
||||||
|
dx = dx / distance;
|
||||||
|
dy = dy / distance;
|
||||||
|
|
||||||
|
local strength = FORCE_SPRING * distance;
|
||||||
|
applyForce( dx * strength, dy * strength );
|
||||||
|
end
|
||||||
|
|
||||||
|
function self:repelFrom( node )
|
||||||
|
local dx, dy = px - node:getX(), py - node:getY();
|
||||||
|
local distance = math.sqrt(dx * dx + dy * dy);
|
||||||
|
dx = dx / distance;
|
||||||
|
dy = dy / distance;
|
||||||
|
|
||||||
|
local mass = 0.015 * (0 + math.log(math.max(24, 0)));
|
||||||
|
local strength = FORCE_CHARGE * ((mass) / (distance * distance));
|
||||||
|
applyForce(dx * strength, dy * strength);
|
||||||
|
end
|
||||||
|
|
||||||
|
---
|
||||||
|
-- Update the node's position based on the calculated velocity and
|
||||||
|
-- acceleration.
|
||||||
|
--
|
||||||
|
function self:move( dt )
|
||||||
|
vx = (vx + ax * dt * NODE_SPEED) * DAMPING_FACTOR;
|
||||||
|
vy = (vy + ay * dt * NODE_SPEED) * DAMPING_FACTOR;
|
||||||
|
px = px + vx;
|
||||||
|
py = py + vy;
|
||||||
|
ax, ay = 0, 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
---
|
||||||
|
-- Returns the node's unique identifier.
|
||||||
|
--
|
||||||
|
function self:getID()
|
||||||
|
return id;
|
||||||
|
end
|
||||||
|
|
||||||
|
function self:getX()
|
||||||
|
return px;
|
||||||
|
end
|
||||||
|
|
||||||
|
function self:getY()
|
||||||
|
return py;
|
||||||
|
end
|
||||||
|
|
||||||
|
function self:getPosition()
|
||||||
|
return px, py;
|
||||||
|
end
|
||||||
|
|
||||||
|
function self:setPosition( nx, ny )
|
||||||
|
px, py = nx, ny;
|
||||||
|
end
|
||||||
|
|
||||||
|
return self;
|
||||||
|
end
|
||||||
|
|
||||||
|
return Node;
|
Loading…
Reference in New Issue
Block a user