summaryrefslogtreecommitdiff
path: root/Graph.py
blob: 49f0378054dc52971174bc290e247ba96aad1523 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import math
import random
import pygame
from parse import parse_input
from Node import Node
from globals import *

def createColorFromString(s):
    i = hash(s)
    r = (i & 0xFF0000) >> 16
    g = (i & 0x00FF00) >> 8
    b = (i & 0x0000FF) + 125;
    return (r,g,b%125 + 100)

def generateRandomVelocity():
    dx = random.uniform(NODE_MIN_VEL, NODE_MAX_VEL)
    dy = random.uniform(NODE_MIN_VEL, NODE_MAX_VEL)
    randomVelocity = (dx, dy)
    return randomVelocity

class Graph(object):
    # A directed graph which contains nodes
    def __init__(self, surface, nodes=[], links=[], file=""):
        self.surface = surface
        self.nodes   = nodes
        self.links   = links
        self.hashLink= {} # This will provide faster access to links
        self.file    = file
        self.font    = pygame.font.SysFont(None, 15)

        self.nodesUnderMouse = []

    def fromFile(self, initializeWithRandomVels=True):
        # Parse from file
        self.nodes, self.links = parse_input(self.file)

        # Set the position of each node
        square = math.ceil(math.sqrt(len(self.nodes)))
        for i in range(square):
            for j in range(square):
                if (i*square + j < len(self.nodes)):
                    self.nodes[i*square + j].pos = (int((WIDTH)/(square) * i + 20), int((HEIGHT)/(square) * j + 20))
                    if (initializeWithRandomVels):
                        self.nodes[i*square + j].vel = generateRandomVelocity()
                    else:
                        self.nodes[i*square + j].vel = (0, 0)
                    self.nodes[i*square + j].color = createColorFromString(self.nodes[square*i + j].text)


    def updateNodePositions(self, dt):
        for i in self.nodes:
            i.update(dt) # Update the position for velocity

    def randomNodes(self):
        # Populate nodes with random ones
        for i in range(10):
            for j in range(10):
                position = (20 + i * 80, 20 + j * 80)
                color=random.choice([RED,GREEN,BLUE])
                radius=random.randint(5, 15)
                text=random.choice(list("ABCDEFGHIJKLMNOPQRSTUVWXYZ"))
                self.nodes.append(Node(position, generateRandomVelocity(), color, radius, text))

    def randomLinks(self):
        for i in range(random.randint(1, 1000)):
            # Each link is (source, destination, weight)
            self.links.append((random.choice(self.nodes), random.choice(self.nodes), 1, "BRUH"))

    def updateHashLinks(self):
        # This will also calculate the radius for each node
        for i in self.links:
            # Hash links appear in the dictionary as:
            # source_node : [(node1, weight1, description1), (node2, weight2, description2)]
            if (i[0] not in self.hashLink.keys()):
                self.hashLink[i[0]] = []
            self.hashLink[i[0]].append((i[1], i[2], i[3]))
        for i in self.nodes:
            if (i in self.hashLink.keys()):
                i.radius = max(min(len(self.hashLink[i]), NODE_MAX_RADIUS), NODE_MIN_RADIUS)
            else:
                # The node has no outer links
                i.radius = NODE_MIN_RADIUS

    def drawLinks(self, node):
        # Draw all of the links from one node to all of its neighbors
        if (node in self.hashLink.keys()):
            for i in self.hashLink[node]:
                pygame.gfxdraw.line(self.surface, int(node.pos[0]), int(node.pos[1]), int(i[0].pos[0]), int(i[0].pos[1]), RED)
                midPoint = ((i[0].pos[0] + node.pos[0])/2, (i[0].pos[1] + node.pos[1])/2)
                render=self.font.render(i[0].text, True, WHITE)
                self.surface.blit(render, midPoint)
                render=self.font.render(i[2], True, WHITE)
                self.surface.blit(render, (midPoint[0] + 10, midPoint[1]+10))
        else:
            for i in self.links:
                if i[0] == node:
                    pygame.gfxdraw.line(self.surface, int(node.pos[0]), int(node.pos[1]), int(i[1].pos[0]), int(i[1].pos[1]), RED)
                    midPoint = (abs(i[1].pos[0] + node.pos[0])/2, abs(i[1].pos[1] + node.pos[1])/2)
                    render=self.font.render(i[1].text, True, WHITE)
                    self.surface.blit(render, midPoint)
                    render=self.font.render(i[3], True, WHITE)
                    self.surface.blit(render, (midPoint[0] + 10, midPoint[1]+10))

    def draw(self):
        # Draw the graph for i in nodes:
        mouseX = pygame.mouse.get_pos()[0]
        mouseY = pygame.mouse.get_pos()[1]

        if (self.nodesUnderMouse):
            # If the node is under the mouse draw the links and the node
            # content
            for i in self.nodesUnderMouse:
                self.drawLinks(i)
                node=i
                render=self.font.render(node.text, True, WHITE)
                self.surface.blit(render, (node.pos[0]+node.radius, node.pos[1]+node.radius))

        # Now we can finally draw the nodes!
        for i in self.nodes:
            i.draw(self.surface)