Пример #1
0
class DesenhaGrafo():
    """
    Representa a interação entre a camada de interface (GUI) e a
    estrutura Grafo.
    """
    def __init__(self, canvas, callback):
        self.grafo = Grafo()
        self.canvas = canvas
        self.vertices = []	#coordenadas dos vértices
        self.arestas = []	#coordenadas das arestas
        self.selecionados = set()
        self.selecionadas = [] #TODO: mudar esse nome. Usada para arestas.
        self.attCallback(callback)
        self.desenhaGrafo()

    def attCallback(self, func):
        """Recebe a funcao opcoes(peso, label) para chamada nessa classe"""
        self.callback = func

    def getVerticePos(self, vertice):
        """Retorna as coordenadas do vertice do grafo"""
        return self.vertices[vertice]

    def setVerticePos(self, vertice, coordenadas):
        """Seta as coordenadas do vertice do grafo"""
        self.vertices[vertice] = coordenadas
        self.canvas.move('vertice', *coordenadas)
        self.canvas.update()

    def colideVerticeAresta(self, coord, raio, checaVertice = True):
        """Checa colisao entre o vertice(passado como parametro por meio das coordenadas e raio), os demais vertices e as arestas"""
        xca, yca, xcb, ycb = coord[0]-raio, coord[1]-raio, coord[0]+raio, coord[1]+raio
        if checaVertice:
            for x,y in self.vertices:
                xa, ya, xb, yb = x-raio, y-raio, x+raio, y+raio
                if xa <= xca <= xb and ya <= yca <= yb:
                    return (True,True)
                elif xa <= xcb <= xb and ya <= ycb <= yb:
                    return (True,True)
                elif xa <= xcb <= xb and ya <= yca <= yb:
                    return (True,True)
                elif xa <= xca <= xb and ya <= ycb <= yb:
                    return (True,True)

        #as quatros retas represetam o quadrado que envolve o vertice
        retaA = Reta((xca,yca,xcb,yca))
        retaB = Reta((xca,yca,xca,ycb))
        retaC = Reta((xcb,yca,xcb,ycb))
        retaD = Reta((xca,ycb,xcb,ycb))
        #################################################################
        for xra,yra,xrb,yrb,va,vb in self.arestas:
            #faz a checagem se houve algum cruzamento das retas
            retaX = Reta((xra,yra,xrb,yrb))
            if retaX.checaInter(retaA) or retaX.checaInter(retaB) or retaX.checaInter(retaC) or retaX.checaInter(retaD):
                return (True,va,vb)

        return (False,False)

    def colidePontoVertice(self, coord, raio):
        """Checa se um ponto colide com algum vertice do grafo, ele retorna o vertice que colodiu"""
        for n in range(len(self.vertices)):
            x, y = self.vertices[n][0], self.vertices[n][1]
            xa, ya, xb, yb = x-raio, y-raio, x+raio, y+raio
            if xa < coord[0] < xb and ya < coord[1] < yb:
                return n
        return -1

    def colidePontoAresta(self, coord, raio):
        """Checa se um ponto colide com alguma aresta do grafo"""
        for x,y in self.vertices:
            xca, yca, xcb, ycb = x-raio, y-raio, x+raio, y+raio
            retaA = Reta((xca,yca,xcb,yca))
            retaB = Reta((xca,yca,xca,ycb))
            retaC = Reta((xcb,yca,xcb,ycb))
            retaD = Reta((xca,ycb,xcb,ycb))
            retaX = Reta(coord)
            if retaX.checaInter(retaA) or retaX.checaInter(retaB) or retaX.checaInter(retaC) or retaX.checaInter(retaD):
                return True
        return False

    def desenhaVertice(self, coordenadas, label=None):
        """Cria um novo vertice e o printa na tela, caso nao colida com nenhum outro vertice ou uma aresta"""
        b = self.colideVerticeAresta(coordenadas, cfg.TAM_VERTICE)
        if not b[0]:
            self.grafo.addVertice(label)
            self.vertices.append(coordenadas)
            self.desenhaGrafo()
        else:
            print 'colidiu mah!!!'

    def apagaVertice(self, coordenadas):
        """Apaga o vertice que tem (x,y) =  coordenadas, caso exista tal vertice"""
        nvertice = self.colidePontoVertice(coordenadas, cfg.TAM_VERTICE)
        if nvertice > -1:
            self.grafo.remVertice(nvertice)
            del self.vertices[nvertice]
            self.desenhaGrafo()
        else:
            print 'nao colidiu mah!!!'

    def apagaAresta(self,coordenadas):
        """Apaga a aresta caso ela contenha (x,y) = coordenadas"""
        x,y = coordenadas
        b = self.colideVerticeAresta(coordenadas, cfg.TAM_VERTICE-20, False)
        if b[0]:
                self.grafo.remAresta((b[1],b[2]))
        self.desenhaGrafo()

    def selecionaVertice(self, coordenadas,peso = -1, dir = 0, add = True):
        """Seleciona um vertice. Se ja houver um outro vertice selecionado e o modo aresta estiver ativo uma nova aresta é feita
        entre os vertices selecionados"""
        nvertice = self.colidePontoVertice(coordenadas, cfg.TAM_VERTICE)
        if nvertice > -1:
            if nvertice not in self.selecionados:
                if len(self.selecionados) > 0:
                    if add ==  True:
                        aux = self.selecionados.pop()
                        self.grafo.addAresta((aux, nvertice),peso)
                        if dir == 0:
                            self.grafo.addAresta((nvertice, aux),peso)
                        nvertice = -1
                else:
                    self.selecionados.add(nvertice)
            else:
                self.selecionados.remove(nvertice)
                nvertice = -1
            self.desenhaGrafo()
        else:
            self.selecionados.clear()
            self.desenhaGrafo()
            print 'num selecionou ninguem!!!'
        return nvertice

    def moverTodos(self, posicao):
        """Move todo o grafo"""
        print posicao
        dx, dy = posicao
        for i, vertice in enumerate(self.vertices):
            self.vertices[i] = (vertice[0] + dx, vertice[1] + dy)
        print self.vertices
        self.desenhaGrafo()

    def buscaProfundidade(self, verticePos):
        """Chama o método de busca de pronfudidade do grafo e pisca os vertices passado por ele"""
        inicial = self.colidePontoVertice(verticePos, cfg.TAM_VERTICE)
        ordem = self.grafo.buscaProfundidade(inicial)
        self.animaGrafo(ordem,1.0)
        print ordem

    def buscaLargura(self, verticePos):
        """Chama o método de busca por largura do grafo e pisca os vertices passado por ele"""
        inicial = self.colidePontoVertice(verticePos, cfg.TAM_VERTICE)
        ordem = self.grafo.buscaLargura(inicial)
        self.animaGrafo(ordem,1.0)
        print ordem

    def agmPrim(self):
        """Chama a o metodo de prim do grafo e muda o cor das arestas da arvore geradora minima"""
        ordem = self.grafo.agmPrim()
        self.selecionadas.extend(ordem)
        self.desenhaGrafo()

    def agmKruskal(self):
        """Chama a o metodo de Kruskal do grafo e muda o cor das arestas da arvore geradora minima"""
        ordem = self.grafo.agmKruskal()
        print ordem
        self.selecionadas.extend(ordem)
        self.desenhaGrafo()

    def colorir(self):
        """Chama o metodo de coloracao do grafo e os colore na tela"""
        cores = self.grafo.colorir()
        self.coloreGrafo(cores)


    def _gerarCores(self, n):
        """Gera as coloracoe dos vertices"""
        print 'gerar', n, 'cores'
        lista = []
        i = 0
        repetir = False
        while i < n:
            repetir = False
            novacor = random.randint(0,255), random.randint(0,255), random.randint(0,255)
            print novacor
            for cor in lista:
                dif = abs(cor[0] - novacor[0]) + abs(cor[1] - novacor[1]) + abs(cor[2] - novacor[2])
                print dif,
                if dif < 20:
                    repetir = True
                    break
            if not repetir:
                lista.append(novacor)
                i += 1
        return lista


    def coloreGrafo(self, cores):
        """Faz a coloracao dos vertices"""
        ncores = max(cores)
        listaCores = self._gerarCores(ncores)
        for indice in range(len(self.vertices)):
            x, y = self.vertices[indice]
            self.circuloFull((x,y), cfg.TAM_VERTICE, str(indice), "#%02x%02x%02x" % listaCores[cores[indice]-1])


    def circuloFull(self, centro, raio, tag, ccor = None):
        """Cria um novo circulo de outra cor por cima dos vertices"""
        x, y = centro
        cor = cfg.COR_VERTICE
        gamb = int(tag)	#TODO: warning: gambiarra...
        if gamb in self.selecionados:
            cor = cfg.COR_SELECIONADA
        elif ccor is not None:
            cor = ccor
        self.canvas.create_oval(x-raio, y-raio, x+raio,y+raio, tag=tag, fill=cor,outline=cor, width=2)


    def minDijkstra(self,sour,dest):
        """Chama a o metodo de Dijkstra para menor caminho do grafo e muda o cor das arestas mostrando qual e esse caminho"""
        ordem = self.grafo.min_dijkstra(sour,dest)
        print ordem
        self.selecionadas.extend(ordem)
        self.desenhaGrafo()

    def minBellman(self,sour,dest):
        """Chama a o metodo de Bellman para menor caminho do grafo e muda o cor das arestas mostrando qual e esse caminho"""
        ordem = self.grafo.minBellman(sour,dest)
        print ordem
        self.selecionadas.extend(ordem)
        self.desenhaGrafo()

    #TODO: refatorar essa funcao. Muitos parametros.
    def circulo(self, centro, raio, tag, ccor = None):
        """Desenha um circulo na tela"""
        x, y = centro
        cor = cfg.COR_VERTICE
        gamb = int(tag)	#TODO: warning: gambiarra...
        if gamb in self.selecionados:
            cor = cfg.COR_SELECIONADA
        elif ccor is not None:
            cor = ccor
        self.canvas.create_oval(x-raio, y-raio, x+raio,y+raio, tag=tag, outline=cor, width=2)

    def animaGrafo(self, lista, passo=cfg.ANM_PASSO):
        """Metódo que faz animacao nos metodos de busca"""
        self.selecionados.clear()
        self.desenhaGrafo()
        self.canvas.update()
        time.sleep(passo)
        back = -1
        for indice in lista:
            if back >= 0:
                self.circulo(self.vertices[back], cfg.TAM_VERTICE, str(indice),ccor=cfg.COR_ANIMACAO2)
                self.canvas.create_text(self.vertices[back],text=str(back),fill=cfg.COR_TEXTO1)
            self.circulo(self.vertices[indice], cfg.TAM_VERTICE, str(indice),ccor=cfg.COR_ANIMACAO1)
            self.canvas.create_text(self.vertices[indice],text=str(indice),fill=cfg.COR_TEXTO1)
            back = indice
            self.canvas.update()
            time.sleep(passo)
        time.sleep(passo)
        self.desenhaGrafo()

    def tremerGrafo(self):
        """Faz a tela tremer de um modo nao muito bonito"""
        y=10
        for x in range(1,20):
            self.canvas.move('all',x,y)
            self.canvas.update()
            time.sleep(0.1)
            self.canvas.move('all',-x,-y)
            self.canvas.update()
            y-=1
            time.sleep(0.1)
        for x in range(20,1,-1):
            self.canvas.move('all',x,y)
            self.canvas.update()
            time.sleep(0.1)
            self.canvas.move('all',-x,-y)
            self.canvas.update()
            time.sleep(0.1)
            y+=1

    def desenhaGrafo(self):
        """Faz todo o tratamento para reprintar todo o grafo na tela"""
        w,h = self.canvas["width"],self.canvas["height"]
        self.canvas.delete('all')
        self.canvas.create_rectangle(0, 0, w, h, fill=cfg.COR_TELA)
        self.arestas = []	#TODO: pensar se seria melhor fazer self.arestas[:] = []
        raio = cfg.TAM_VERTICE
        peso, direcao, label = self.callback()

        for indice in range(len(self.vertices)):
            x, y = self.vertices[indice]
            self.circulo((x,y), cfg.TAM_VERTICE, str(indice))
            if label == 0:
                self.canvas.create_text(self.vertices[indice],text=str(indice), tag = str(indice), activefill="#405252", fill=cfg.COR_TEXTO2)
            else:
                self.canvas.create_text(self.vertices[indice],text=self.grafo.labels[indice], tag = str(indice), activefill="#405252", fill=cfg.COR_TEXTO2)

        for va in range(len(self.grafo.matriz)):
            arestas = self.grafo.matriz[va]
            for vb, pesob in arestas:
                xa, ya = self.vertices[va]
                xb, yb = self.vertices[vb]
                #print pesob
                ang = math.atan2(xb-xa, yb-ya)
                ang2 = math.atan2(xa-xb, ya-yb)
                #print int(15*math.cos(ang)), int(15*math.sin(ang))
                if peso == 1:
                    self.canvas.create_text(((xb+xa)/2 + int(15*math.sin(ang+1.57)),
                        (ya+yb)/2 + int(15*math.cos(ang+1.57))), text=str(pesob),
                        tag = str(va)+'-'+str(vb), fill=cfg.COR_SELECIONADA)
                x, y = xa + raio * math.sin(ang), ya + raio * math.cos(ang)
                x2, y2 = xb + raio * math.sin(ang2), yb + raio * math.cos(ang2)
                cor = 'white'
                if (va, vb) in self.selecionadas or (vb, va) in self.selecionadas:
                    cor = cfg.COR_ARESTA2
                self.canvas.create_line(x,y,x2,y2, tag=str(va)+'-'+str(vb), fill=cor,width=2, arrow="last")
                self.arestas.append((x,y,x2,y2,va,vb))
        self.selecionadas = []

    def info(self):
        """Fornece informacoes sobre a estrutura."""
        info = []
        info.append(len(self.vertices))
        for a,b in self.vertices:
            info.append(a)
            info.append(b)
        info.extend(self.grafo.info())
        return info

    def carregar(self, info):
        """Carrega o grafo e desenha na tela"""
        indice, nvertices = 1, int(info[0])
        while (indice < 2 * nvertices + 1):
            self.vertices.append((int(info[indice]), int(info[indice+1])))
            indice += 2
        self.grafo.carregar(info[2 * nvertices + 1:])
        self.desenhaGrafo()