Skip to content

Commit ee8885a

Browse files
committed
Merge branch 'release/1.0.0'
2 parents ff55890 + 138578e commit ee8885a

File tree

8 files changed

+499
-3
lines changed

8 files changed

+499
-3
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
# CHANGELOG
1+
## Version 1.0.0 ( 2016-01-12 )
2+
- Initial Release

Graphoon.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
return require( (...) .. '.init' );

Graphoon/Edge.lua

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
local current = (...):gsub('%.[^%.]+$', '');
2+
3+
local Edge = {};
4+
5+
function Edge.new( id, origin, target )
6+
local self = {};
7+
8+
self.id = id;
9+
self.origin = origin;
10+
self.target = target;
11+
12+
return self;
13+
end
14+
15+
return Edge;

Graphoon/Graph.lua

Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,262 @@
1+
local current = (...):gsub('%.[^%.]+$', '');
2+
3+
-- ------------------------------------------------
4+
-- Required Modules
5+
-- ------------------------------------------------
6+
7+
local Node = require(current .. '.Node');
8+
local Edge = require(current .. '.Edge');
9+
10+
-- ------------------------------------------------
11+
-- Module
12+
-- ------------------------------------------------
13+
14+
local Graph = {};
15+
16+
function Graph.new()
17+
local self = {};
18+
19+
local nodes = {}; -- Contains all nodes in the graph.
20+
local edges = {}; -- Contains all edges in the graph.
21+
local edgeIDs = 0; -- Used to create a unique ID for new edges.
22+
23+
local minX, maxX, minY, maxY; -- The boundaries of the graph.
24+
25+
-- ------------------------------------------------
26+
-- Local Functions
27+
-- ------------------------------------------------
28+
29+
---
30+
-- (Re-)Sets the graph's boundaries to nil.
31+
--
32+
local function resetBoundaries()
33+
minX, maxX, minY, maxY = nil, nil, nil, nil;
34+
end
35+
36+
---
37+
-- Updates the boundaries of the graph.
38+
-- This represents the rectangular area in which all nodes are contained.
39+
-- @param minX - The current minimum x position.
40+
-- @param maxX - The current maximum y position.
41+
-- @param minY - The current minimum x position.
42+
-- @param maxY - The current maximum y position.
43+
-- @param nx - The new x position to check.
44+
-- @param ny - The new y position to check.
45+
--
46+
local function updateBoundaries( minX, maxX, minY, maxY, nx, ny )
47+
return math.min( minX or nx, nx ), math.max( maxX or nx, nx ), math.min( minY or ny, ny ), math.max( maxY or ny, ny );
48+
end
49+
50+
---
51+
-- Adds a new edge between two nodes.
52+
-- @param origin - The node from which the edge originates.
53+
-- @param target - The node to which the edge is pointing to.
54+
--
55+
local function addEdge( origin, target )
56+
for _, edge in pairs( edges ) do
57+
if edge.origin == origin and edge.target == target then
58+
error "Trying to connect nodes which are already connected.";
59+
end
60+
end
61+
62+
assert( origin ~= target, "Tried to connect a node with itself." );
63+
edges[edgeIDs] = Edge.new( edgeIDs, origin, target );
64+
edgeIDs = edgeIDs + 1;
65+
end
66+
67+
-- ------------------------------------------------
68+
-- Public Functions
69+
-- ------------------------------------------------
70+
71+
---
72+
-- Adds a node to the graph.
73+
-- @param id - The ID will be used to reference the Node inside of the graph.
74+
-- @param x - The x coordinate the Node should be spawned at (optional).
75+
-- @param y - The y coordinate the Node should be spawned at (optional).
76+
-- @param anchor - Wether the node should be locked in place or not (optional).
77+
-- @param ... - Additional parameters (useful when a custom Node class is used).
78+
--
79+
function self:addNode( id, x, y, anchor, ... )
80+
assert( not nodes[id], "Node IDs must be unique." );
81+
nodes[id] = Node.new( id, x, y, anchor, ... );
82+
return nodes[id];
83+
end
84+
85+
---
86+
-- Removes a node from the graph.
87+
-- This will also remove all edges pointing to, or originating from this
88+
-- node.
89+
-- @param node - The node to remove from the graph.
90+
--
91+
function self:removeNode( node )
92+
nodes[node:getID()] = nil;
93+
94+
self:removeEdges( node );
95+
end
96+
97+
---
98+
-- Adds a new edge between two nodes.
99+
-- @param origin - The node from which the edge originates.
100+
-- @param target - The node to which the edge is pointing to.
101+
--
102+
function self:connectNodes( origin, target )
103+
addEdge( origin, target );
104+
end
105+
106+
---
107+
-- Adds a new edge between two nodes referenced by their IDs.
108+
-- @param origin - The node id from which the edge originates.
109+
-- @param target - The node id to which the edge is pointing to.
110+
--
111+
function self:connectIDs( originID, targetID )
112+
assert( nodes[originID], string.format( "Tried to add an Edge to the nonexistent Node \"%s\".", originID ));
113+
assert( nodes[targetID], string.format( "Tried to add an Edge to the nonexistent Node \"%s\".", targetID ));
114+
addEdge( nodes[originID], nodes[targetID] );
115+
end
116+
117+
---
118+
-- Removes all edges leading to, or originating from a node.
119+
-- @param node - The node to remove all edges from.
120+
--
121+
function self:removeEdges( node )
122+
for id, edge in pairs( edges ) do
123+
if edge.origin == node or edge.target == node then
124+
edges[id] = nil;
125+
end
126+
end
127+
end
128+
129+
---
130+
-- Updates the graph.
131+
-- @param dt - The delta time between frames.
132+
-- @param nodeCallback - A callback called on every node (optional).
133+
-- @param edgeCallback - A callback called on every edge (optional).
134+
--
135+
function self:update( dt, nodeCallback, edgeCallback )
136+
for _, edge in pairs( edges ) do
137+
edge.origin:attractTo( edge.target );
138+
edge.target:attractTo( edge.origin );
139+
140+
if edgeCallback then
141+
edgeCallback( edge );
142+
end
143+
end
144+
145+
resetBoundaries();
146+
147+
for _, nodeA in pairs( nodes ) do
148+
if not nodeA:isAnchor() then
149+
for _, nodeB in pairs( nodes ) do
150+
if nodeA ~= nodeB then
151+
nodeA:repelFrom( nodeB );
152+
end
153+
end
154+
nodeA:move( dt );
155+
end
156+
157+
if nodeCallback then
158+
nodeCallback( nodeA );
159+
end
160+
161+
minX, maxX, minY, maxY = updateBoundaries( minX, maxX, minY, maxY, nodeA:getPosition() );
162+
end
163+
end
164+
165+
---
166+
-- Draws the graph.
167+
-- Takes two callback functions as a parameter. These will be called
168+
-- on each edge and node in the graph and will be used to wite a custom
169+
-- drawing function.
170+
-- @param nodeCallback - A callback called on every node.
171+
-- @param edgeCallback - A callback called on every edge.
172+
--
173+
function self:draw( nodeCallback, edgeCallback )
174+
for _, edge in pairs( edges ) do
175+
if not edgeCallback then break end
176+
edgeCallback( edge );
177+
end
178+
179+
for _, node in pairs( nodes ) do
180+
if not nodeCallback then break end
181+
nodeCallback( node );
182+
end
183+
end
184+
185+
---
186+
-- Checks if a certain Node ID already exists.
187+
-- @param id - The id to check for.
188+
--
189+
function self:hasNode( id )
190+
return nodes[id] ~= nil;
191+
end
192+
193+
---
194+
-- Returns the node the id is pointing to.
195+
-- @param id - The id to check for.
196+
--
197+
function self:getNode( id )
198+
return nodes[id];
199+
end
200+
201+
---
202+
-- Gets a node at a certain point in the graph.
203+
-- @param x - The x coordinate to check.
204+
-- @param y - The y coordinate to check.
205+
-- @param range - The range in which to check around the given coordinates.
206+
--
207+
function self:getNodeAt(x, y, range)
208+
for _, node in pairs( nodes ) do
209+
local nx, ny = node:getPosition();
210+
if x < nx + range and x > nx - range and y < ny + range and y > ny - range then
211+
return node;
212+
end
213+
end
214+
end
215+
216+
---
217+
-- Returns the graph's minimum and maxmimum x and y values.
218+
--
219+
function self:getBoundaries()
220+
return minX, maxX, minY, maxY;
221+
end
222+
223+
---
224+
-- Returns the x and y coordinates of the graph's center.
225+
--
226+
function self:getCenter()
227+
return ( ( maxX - minX ) * 0.5 ) + minX, ( ( maxY - minY ) * 0.5 ) + minY;
228+
end
229+
230+
---
231+
-- Turn a node into an anchor.
232+
-- Anchored nodes have fixed positions and can't be moved by the physical
233+
-- forces.
234+
-- @param id - The node's id.
235+
-- @param x - The x coordinate to anchor the node to.
236+
-- @param y - The y coordinate to anchor the node to.
237+
--
238+
function self:setAnchor( id, x, y )
239+
nodes[id]:setPosition( x, y );
240+
nodes[id]:setAnchor( true );
241+
end
242+
243+
return self;
244+
end
245+
246+
---
247+
-- Replaces the default Edge class with a custom one.
248+
-- @param class - The custom Edge class to use.
249+
--
250+
function Graph.setEdgeClass( class )
251+
Edge = class;
252+
end
253+
254+
---
255+
-- Replaces the default Node class with a custom one.
256+
-- @param class - The custom Node class to use.
257+
--
258+
function Graph.setNodeClass( class )
259+
Node = class;
260+
end
261+
262+
return Graph;

0 commit comments

Comments
 (0)