def __init__(self, mat=[]):
     '''
     Inicializa os atributos e variáveis da classe
     params:
         mat -> list
             Opcional - lista de campos de gradientes que serão análisados
     '''
     self.ui = Analise_View(self)
     self.ui.showMaximized()
     self.matrizes = mat
     self.figuras_vet = []
     self.GAs = []
     self.figuras_triang = []
     self.figuras_GA = []
     self.pos = 0
     self.current_tab = 0
     if len(self.matrizes) > 0:
         self.ABERTURA = 'direta'
         self.normalizado = False
     else:
         self.ABERTURA = 'normal'
class Analise_Ctrl:
    '''
    Controla o funcionamento do módulo de análise de gradientes
    '''
    def __init__(self, mat=[]):
        '''
        Inicializa os atributos e variáveis da classe
        params:
            mat -> list
                Opcional - lista de campos de gradientes que serão análisados
        '''
        self.ui = Analise_View(self)
        self.ui.showMaximized()
        self.matrizes = mat
        self.figuras_vet = []
        self.GAs = []
        self.figuras_triang = []
        self.figuras_GA = []
        self.pos = 0
        self.current_tab = 0
        if len(self.matrizes) > 0:
            self.ABERTURA = 'direta'
            self.normalizado = False
        else:
            self.ABERTURA = 'normal'
        
    def incrementa_view(self):
        '''
        Muda o conjunto de dados sendo exibido para o próximo da ‭lista
        '''
        
        print 'incremented'
        self.pos += 1
        if self.current_tab == 0:
            self.ui.ui.stackedGraphics.setCurrentIndex(self.pos)
        elif self.current_tab == 1:
            self.ui.ui.stackedVet.setCurrentIndex(self.pos)
        elif self.current_tab == 2:
            self.ui.ui.stackedTriang.setCurrentIndex(self.pos)
        else:
            self.ui.ui.stackedGPA.setCurrentIndex(self.pos)
        self.ui.ui.horizontalSlider.setValue(self.pos)
        time.sleep(.10)
    
    def set_current_tab(self, tab):
        '''
        Ajusta a aba que deve ser exibida
        params: 
            tab -> int 
                indice da aba que será exibida
        '''
        
        self.current_tab = tab
        self.set_view(self.pos)
        
    def decrementa_view(self):
        '''
        Muda o conjunto de dados sendo exibido para o anterior da ‭lista
        '''
        
        print 'decremented'
        self.pos -= 1
        if self.current_tab == 0:
            self.ui.ui.stackedGraphics.setCurrentIndex(self.pos)
        elif self.current_tab == 1:
            self.ui.ui.stackedVet.setCurrentIndex(self.pos)
        elif self.current_tab == 2:
            self.ui.ui.stackedTriang.setCurrentIndex(self.pos)
        else:
            self.ui.ui.stackedGPA.setCurrentIndex(self.pos)
        self.ui.ui.horizontalSlider.setValue(self.pos)
        time.sleep(.10)
                
    def last_view(self):
        '''
        Muda a exibição para o último conjunto da ‭lista
        '''
        print 'last'
        self.pos = self.ui.ui.stackedGraphics.count() - 1
        self.ui.ui.stackedGraphics.setCurrentIndex(self.pos)
        self.ui.ui.stackedVet.setCurrentIndex(self.pos)
        self.ui.ui.stackedTriang.setCurrentIndex(self.pos)
        self.ui.ui.stackedGPA.setCurrentIndex(self.pos)
        self.ui.ui.horizontalSlider.setValue(self.pos)
    
    def first_view(self):
        '''
        Muda a exibição para o prieiro conjunto da ‭lista
        '''
        print 'first'
        self.pos = 0
        self.ui.ui.stackedGraphics.setCurrentIndex(self.pos)
        self.ui.ui.stackedVet.setCurrentIndex(self.pos)
        self.ui.ui.stackedTriang.setCurrentIndex(self.pos)
        self.ui.ui.stackedGPA.setCurrentIndex(self.pos)
        self.ui.ui.horizontalSlider.setValue(self.pos)
        time.sleep(.10)
                
    def set_view(self, pos):
        '''
        Ajusta a posição da ‭lista de dados para a posição passada como
        parâmetro
        params:
            pos -> int
                Posição da ‭lista que será exibida
        '''
        
        print 'set ' + str(pos)
        self.pos = pos
        self.ui.ui.stackedGraphics.setCurrentIndex(self.pos)
        self.ui.ui.stackedVet.setCurrentIndex(self.pos)
        self.ui.ui.stackedTriang.setCurrentIndex(self.pos)
        self.ui.ui.stackedGPA.setCurrentIndex(self.pos)
        self.ui.ui.horizontalSlider.setValue(self.pos)
        time.sleep(.10)
                
    def abrir_arquivo(self):
        '''
        Abre um arquivo contendo uma matriz bidimensional de dados ou uma 
        imagem e gera a matriz de dados interna do programa
        '''
        
        self.figuras_vet = []
        self.figuras_triang = []
        self.figuras_GA = []
        self.normalizado = False
        self.matrizes = []
        fd = QtGui.QFileDialog()
        file_path = fd.getOpenFileName(parent=None,
                                caption=u'Abrir arquivo',
        filter=u'Dados textuais (*.txt *.dat);;Imagens (*.png *.bmp *.jpg)')
        if file_path[-3:] in ['png', 'jpg', 'bmp']:
            try:
                im = Image.open(str(file_path), 'r')
                mat = []
                im = im.convert('L')
                im.show()
                w, h = im.size
                mat = []
                dlg = QtGui.QProgressDialog(u'Lendo Arquivo', u'Cancelar',
                                        0, h)
                dlg.setModal(True)
                dlg.setMinimumDuration(0)
                dlg.setAutoClose(True)
                dlg.setWindowTitle(u'Leitura de Arquivo')
                dlg.show()
                for i in xrange(h):
                    line = []
                    for j in xrange(w):
                        line.append(im.getpixel((j, i)))
                    mat.append(line)
                    dlg.setValue(i)
                    if dlg.wasCanceled():
                        return
                mat.reverse()
                self.matriz = mat[:]
            except IOError as e:
                print('Abertura de arquivo falhou ' + str(e))
                return
        else:
            try:
                f = open(str(file_path), 'r')
            except IOError as e:
                print('Abertura de arquivo falhou ' + str(e))
                return
            supermatriz = []
            matriz = []
            mat_lines = f.readlines()
            self.matriz = []
            a = 0
            if mat_lines[-1] == '':
                mat_lines.pop()
            for line in mat_lines:
                a += 1
                if line == '\n':
                    matriz.reverse()
                    supermatriz.append(matriz[:])
                    matriz = []
                    continue
                row = line.strip('\n').split(' ')
                if row[-1] == '':
                    matriz.append([eval(e) for e in row[:-1]])
                else:
                    matriz.append([eval(e) for e in row])
                    a += 1
            matriz.reverse()
            supermatriz.append(matriz[:])
            
            f.close()
            self.matrizes = supermatriz[:]
        self.processa_matrizes()
        
        self.first_view()
        
        
    def processa_matrizes(self):
        '''
        Opera sobre o conjunto de matrizes gerando os vetores, 
        triangulações e widgets
        '''
        for mat in self.matrizes:
            self.matriz = mat[:]
            self.gerar_vetores()
            self.gerar_triangulacao()
        self.gerar_grafico_GA()
        self.gerar_widgets()
        
    def gerar_grafico_GA(self):
        '''
        Gera o gráfico de graus de assimetria dos conjuntos de dados
        '''
        
        for i in range(len(self.matrizes)):
            self.figuras_GA.append(Figure(dpi=120))
            axes = self.figuras_GA[-1].add_subplot(111)
            axes.plot(range(len(self.GAs)), self.GAs)
            axes.plot(i, self.GAs[i], 'ro')
            
    def get_dx(self):
        '''
        Gera uma matriz com as derivadas parciais em x para a matriz de
        dados lida
        return:
            mat -> list
                lista que contém as matrizes de derivadas parciais em x
        '''
        
        if self.ABERTURA == 'normal':
            dx = []
            dlg = QtGui.QProgressDialog(u'Calculando dx', u'Cancelar',
                                        0, len(self.matriz[:-1]))
            dlg.setModal(True)
            dlg.setMinimumDuration(0)
            dlg.setAutoClose(True)
            dlg.setWindowTitle(u'Cálculo da derivada')
            dlg.show()
            a = 0

            for linha in self.matriz[:]:
                linha_dx = []
                for i in xrange(len(linha)):
                    if i == 0:
                        linha_dx.append(
                                (-3 * linha[0] + 4 * linha[1] - linha[2]) / 2.0)
                    elif i == len(linha) - 1:
                        linha_dx.append(
                            (3 * linha[-1] - 4 * linha[-2] + linha[-3]) / 2.0)
                    else:
                        linha_dx.append((linha[i + 1] - linha[i - 1]) / 2.0)
                dx.append(linha_dx)
                dlg.setValue(a)
                a += 1
                dlg.close()
            return dx
        else:
            mat = []
            for l in self.matriz[:]:
                mat.append(list(zip(*l)[0]))
            return mat
                

    def get_dy(self):
        '''
        Gera uma matriz com as derivadas parciais em y para a matriz de
        dados lida
        return:
            mat -> list
                lista que contém as matrizes de derivadas parciais em x
        '''
        if self.ABERTURA == 'normal':
            dy = []
            dlg = QtGui.QProgressDialog(u'Calculando dy', u'Cancelar',
                                        0, len(self.matriz[:-1]))
            dlg.setModal(True)
            dlg.setMinimumDuration(0)
            dlg.setAutoClose(True)
            dlg.setWindowTitle(u'Cálculo da derivada')
            dlg.show()
            a = 0
            for linha in zip(*self.matriz[:]):
                linha_dy = []
                for i in xrange(len(linha)):
                    if i == 0:
                        linha_dy.append(
                                        (-3 * linha[0] + 4 * linha[1] - linha[2]) / 2.0)
                    elif i == len(linha) - 1:
                        linha_dy.append(
                                        (3 * linha[-1] - 4 * linha[-2] + linha[-3]) / 2.0)
                    else:
                        linha_dy.append((linha[i + 1] - linha[i - 1]) / 2.0)
                dy.append(linha_dy)
                dlg.setValue(a)
                a += 1
                if dlg.wasCanceled():
                    return
            dlg.close()
            return zip(*dy)
        else:
            mat = []
            for l in self.matriz[:]:
                mat.append(list(zip(*l)[1]))
            return mat
        
    def normaliza_derivadas(self):
        '''
        Normaliza as derivadas em função do maior valor que se tornará 1
        Todos os valores passam a ter norma entre 0 e 1 inclusive
        '''
        if self.normalizado:
            return

        maximo = 0.0

        for linha in self.dx:
            m = max([abs(l) for l in linha])
            if m > maximo:
                maximo = m
        for linha in self.dy:
            m = max([abs(l) for l in linha])
            if m > maximo:
                maximo = m
        self.dx = [[d / float(maximo) for d in linha] for linha in self.dx]
        self.dy = [[d / float(maximo) for d in linha] for linha in self.dy]
      
    def gerar_vetores(self):
        '''
        Gera o campo de gradientes do conjunto de dados a partir das derivadas 
        parciais em x e y de cada elemento do conjunto
        '''
        self.dx = self.get_dx()
        self.dy = self.get_dy()

        self.normaliza_derivadas()
        self.anular()

        minx = -1
        maxx = round(max(zip(*self.dx)[-1]))
        miny = -1
        maxy = round(max(self.dy[-1]))

        self.figuras_vet.append(Figure(dpi=120))
        axes = self.figuras_vet[-1].add_subplot(111, aspect='equal')
        q = axes.quiver(self.dx, self.dy, angles='xy', scale=1.0,
                                scale_units='xy', minshaft=2, minlength=1)
        axes.quiverkey(q, 0, miny - 2, 1, '', coordinates='data')
        axes.set_xlim(minx, len(self.dx[0]) + maxx)
        axes.set_ylim(miny, len(self.dx) + maxy)
        
    def anular(self):
        '''
        Coloca norma zero para os pares de vetores que se anulam.
        '''
        vects = [zip(x, y) for x, y in zip(self.dx, self.dy)]
        dlg = QtGui.QProgressDialog(u'Otimizando campo', u'Cancelar',
                                    0, len(vects))
        dlg.setModal(True)
        dlg.setMinimumDuration(0)
        dlg.setAutoClose(True)
        dlg.setWindowTitle(u'Eliminar vetores')
        dlg.show()
        for i in xrange(len(vects)):
            for j in xrange(len(vects[0])):
                for k in xrange(i, len(vects)):
                    for w in xrange(len(vects[0])):
                        a = vects[i][j]
                        b = vects[k][w]
                        if a == (0, 0):
                            break
                        if (a[0] == -b[0]) and (a[1] == -b[1]):
                                vects[i][j] = vects[k][w] = (0, 0)
                                break
            dlg.setValue(i)
            if dlg.wasCanceled():
                return
        dlg.close()
        del(dlg)
        v = [zip(*l) for l in vects]
        self.dx, self.dy = zip(*v)
        
    def gerar_triangulacao(self):
        '''
        Gera a triangulação de Delaunay para o conjunto de dados,
        plota os triângulos e exibe o número de arestas encontradas
        '''
        vects = [zip(x, y) for x, y in zip(self.dx, self.dy)]
        points = []
        for i in xrange(len(vects)):
            line = []
            for j in xrange(len(vects[0])):
                x, y = vects[i][j]
                if (abs(x) > 0.0) or (abs(y) > 0.0):
                    if [x + j, y + i] not in points:
                        line.append([x + j, y + i])
            points += line

        x, y = zip(*points)
        t = tri.Triangulation(x, y)
        self.figuras_triang.append(Figure(dpi=120))
        axes = self.figuras_triang[-1].add_subplot(111, aspect='equal')
        minx = round(min(zip(*self.dx)[0])) - 1
        maxx = round(max(zip(*self.dx)[-1]))
        miny = round(min(self.dy[0])) - 1
        maxy = round(max(self.dy[-1]))
        if miny >= 0:
            miny = -1
        if minx >= 0:
            minx = -1
        axes.set_xlim(minx, len(self.dx[0]) + maxx)
        axes.set_ylim(miny, len(self.dx) + maxy)
        axes.triplot(t)

        self.GAs.append((len(t.edges) - len(x)) / float(len(x)))
        
    def gerar_widgets(self):
        '''
        Gera todos os widgets dos gráficos que serão colocados nas telas
        '''
        for indice in range(len(self.matrizes)):
            graph_widget = Grafics_widget()
            graph_widget.setup()
            
            widget_delaunay = FigureWidget(self.figuras_triang[indice])
            widget_delaunay.setObjectName(_fromUtf8("widget_delaunay"))
            widget_delaunay.setParent(graph_widget.groupBox_2)
            graph_widget.gridLayout_4.addWidget(widget_delaunay, 0, 0, 1, 1)
            
            widget_vector = FigureWidget(self.figuras_vet[indice])
            widget_vector.setObjectName(_fromUtf8("widget_vector"))
            widget_vector.setParent(graph_widget.groupBox)
            graph_widget.gridLayout_3.addWidget(widget_vector, 0, 0, 1, 1)
            
            graph_widget.label.setText("%1.6f" % self.GAs[indice])
            
            vect_widget = Detail_widget()
            vect_widget.setup()
            
            widget_vector_tab = FigureWidget(self.figuras_vet[indice])
            widget_vector_tab.setObjectName(_fromUtf8("widget_vector_tab"))
            widget_vector_tab.setParent(vect_widget.groupBox)
            vect_widget.gridLayout_1.addWidget(widget_vector_tab, 0, 0, 1, 1)
            
            navbar_vetor = Navbar(widget_vector_tab, self.ui.ui.centralwidget)
            vect_widget.gridLayout_2.addWidget(navbar_vetor, 0, 0, 1, 1)
            
            trian_widget = Detail_widget()
            trian_widget.setup()
            
            widget_delaunay_tab = FigureWidget(self.figuras_triang[indice])
            widget_delaunay_tab.setObjectName(_fromUtf8("widget_delaunay_tab"))
            widget_delaunay_tab.setParent(trian_widget.groupBox)
            trian_widget.gridLayout_1.addWidget(widget_delaunay_tab, 0, 0, 1, 1)
            
            navbar_delaunay = Navbar(widget_delaunay_tab, self.ui.ui.centralwidget)
            trian_widget.gridLayout_2.addWidget(navbar_delaunay, 0, 0, 1, 1)
        
            widget_gpa_ev = FigureWidget(self.figuras_GA[indice])
            widget_gpa_ev.setObjectName(_fromUtf8("widget_gpa_ev"))
            widget_gpa_ev.setParent(self.ui.ui.GPAGraphGroup)
            
            self.ui.ui.stackedGraphics.addWidget(graph_widget)
            self.ui.ui.stackedVet.addWidget(vect_widget)
            self.ui.ui.stackedTriang.addWidget(trian_widget)
            self.ui.ui.stackedGPA.addWidget(widget_gpa_ev)
            
        self.ui.ui.horizontalSlider.setMaximum(len(self.matrizes) - 1)
        self.ui.ui.horizontalSlider.setSingleStep(1)
        self.ui.ui.horizontalSlider.setPageStep(1)