Exemplo n.º 1
0
 def set_solution(self, solution):
     """ Receives a solution from search and sets the node """
     self.node = VertexColoringState(
         solution.state,
         None,
         self.num_colors,
         solution.domains,
         solution.solution_length
     )
Exemplo n.º 2
0
    def level_loaded(self, graph):
        """ Called whenever a level is loaded, adjust Widget size """
        self.node = VertexColoringState(graph, None, self.num_colors)

        self.compute_tile_size()
Exemplo n.º 3
0
class GraphGUI(QtGui.QFrame):
    # pylint: disable=too-many-instance-attributes
    """ Implement QFrame, which is a subclass of QWidget """
    status_message = pyqtSignal(str)

    def __init__(self, parent):
        QtGui.QFrame.__init__(self, parent)

        self.dx = self.dy = 1
        self.widget_width_px = self.widget_height_px = 600
        # Adjustments for negative coordinates in graphs.
        self.nc_adjust_x = self.nc_adjust_y = 0
        self.total_height = 0
        self.vertex_radii = 5

        self.num_colors = 4
        self.delay = 50
        self.vertex_numbering = False
        self.node = None
        self.set_graph(True)
        self.mode = C.search_mode.A_STAR
        self.thread = SearchWorker(self)
        self.init_ui()

    def init_ui(self):
        """ Initialize the UI """
        self.setFocusPolicy(QtCore.Qt.StrongFocus)
        size = QtCore.QSize(self.widget_width_px, self.widget_height_px)
        self.setMinimumSize(size)
        self.parent().adjustSize()

    def level_loaded(self, graph):
        """ Called whenever a level is loaded, adjust Widget size """
        self.node = VertexColoringState(graph, None, self.num_colors)

        self.compute_tile_size()

    def compute_tile_size(self):
        """ Computes tile size based on widget size and graph """
        self.nc_adjust_x = self.nc_adjust_y = 0

        width_orig = self.node.state.width
        height_orig = self.node.state.height

        self.dx = self.dy = 1
        self.dx = self.widget_width_px / float(width_orig)
        self.dy = self.widget_height_px / float(height_orig)

        self.nc_adjust_x = self.node.state.min_x * self.dx
        self.nc_adjust_y = self.node.state.min_y * self.dy

    def start_search(self):
        """ Start the search in the worker thread """
        self.status_message.emit(str('Search started'))
        self.thread.search(VertexColoringBfs(self.node.state, self))

    def set_solution(self, solution):
        """ Receives a solution from search and sets the node """
        self.node = VertexColoringState(
            solution.state,
            None,
            self.num_colors,
            solution.domains,
            solution.solution_length
        )

    def paint(self, node):
        """ Receives a node and tells Qt to update the graphics """
        self.node = node
        self.update()

    def paintEvent(self, _): # pylint: disable=invalid-name
        """ Called by the Qt event loop when the widget should be updated """
        if self.node is None:
            return

        painter = QtGui.QPainter(self)
        self.paint_graph(painter)

    def resizeEvent(self, e): # pylint: disable=invalid-name
        """ Handles widget resize and scales Graph """
        self.widget_width_px = e.size().width()
        self.widget_height_px = e.size().height()
        self.compute_tile_size()

    def draw_vertex(self, vertex, painter, whites=False):
        """ Draws a vertex, either all the white nodes (with a domain length
        larger than 1) or all the colored nodes. Also draws optional
        vertex numbers. """
        x = (vertex[1] * self.dx) - self.nc_adjust_x
        y = (vertex[2] * self.dy) - self.nc_adjust_y
        y = self.widget_height_px - y
        point = QtCore.QPoint(x, y)

        colors = {
            C.graph_colors.RED: QtGui.QColor(255, 128, 0),
            C.graph_colors.GREEN: QtGui.QColor(0, 200, 0),
            C.graph_colors.BLUE: QtGui.QColor(0, 0, 255),
            C.graph_colors.ORANGE: QtGui.QColor(175, 0, 100),
            C.graph_colors.PINK: QtGui.QColor(255, 20, 147),
            C.graph_colors.YELLOW: QtGui.QColor(255, 255, 0),
            C.graph_colors.PURPLE: QtGui.QColor(238, 130, 238),
            C.graph_colors.BROWN: QtGui.QColor(222, 184, 135),
            C.graph_colors.CYAN: QtGui.QColor(0, 255, 255),
            C.graph_colors.DARK_BROWN: QtGui.QColor(120, 60, 0),
            C.graph_colors.WHITE: QtGui.QColor(255, 255, 255),
            C.graph_colors.BLACK: QtGui.QColor(0, 0, 0),
        }
        vertex_color = self.node.vertex_color(vertex[0])
        color = colors[vertex_color]

        painter.setPen(color)
        painter.setBrush(color)

        if whites and vertex_color is C.graph_colors.WHITE:
            painter.drawEllipse(point, self.vertex_radii, self.vertex_radii)
        elif not whites and vertex_color is not C.graph_colors.WHITE:
            painter.drawEllipse(point, self.vertex_radii, self.vertex_radii)

        if whites and self.vertex_numbering:
            painter.setPen(colors[C.graph_colors.BLACK])
            painter.drawText(x, y, str(vertex[0]))

    def draw_edge(self, edge, painter):
        """ Draws edge between two vertices """
        v1 = self.node.state.vertices[edge[0]]
        v2 = self.node.state.vertices[edge[1]]

        x1 = (v1[1] * self.dx) - self.nc_adjust_x
        y1 = (v1[2] * self.dy) - self.nc_adjust_y
        x2 = (v2[1] * self.dx) - self.nc_adjust_x
        y2 = (v2[2] * self.dy) - self.nc_adjust_y

        y1, y2 = self.widget_height_px - y1, self.widget_height_px - y2

        p1, p2 = QtCore.QPoint(x1, y1), QtCore.QPoint(x2, y2)

        painter.setPen(QtGui.QColor(120, 120, 120))
        painter.drawLine(p1, p2)

    def paint_graph(self, painter):
        """ The graph is painted by edges, unset and lastly colored vertices """
        for edge in self.node.state.edges:
            self.draw_edge(edge, painter)

        # Draw white vertices first
        for vertex in self.node.state.vertices:
            self.draw_vertex(vertex, painter, True)

        for vertex in reversed(self.node.state.vertices):
            self.draw_vertex(vertex, painter)

    def set_graph(self, default=False):
        """ Load level with a QFileDialog """
        folder = res.graphs.__path__[0]
        if default:
            path = folder + '/graph-color-1.txt'
        else:
            path = QtGui.QFileDialog.getOpenFileName(
                self.window(), "Open graph file", folder, "Text files (*.txt)"
            )
            if not path:
                return

        graph_file = open(path, 'r')
        contents = [line.strip() for line in graph_file.read().splitlines()]

        self.level_loaded(Graph(contents))

        filename = path.split('/')[-1]
        self.parent().setWindowTitle('Module 2 - A*-GAC - {}'.format(filename))
        self.status_message.emit(str('Loaded: {}'.format(filename)))
        self.update()

    def set_color(self, colors):
        """ Change color and notify user """
        self.num_colors = colors
        self.status_message.emit('Amount of colors available: ' + str(colors))

    def set_vertex_numbering(self, numbering):
        """ Boolean numbering decides if we show vertex numbers. """
        self.vertex_numbering = numbering
        if numbering:
            self.status_message.emit('Showing vertex numbers')
        else:
            self.status_message.emit('Hiding vertex numbers')
        self.update()

    def set_delay(self, delay):
        """ Change delay """
        self.delay = delay
        self.status_message.emit('Delay: ' + str(delay))