Example #1
0
def input_aleatorio(tipo, n, max_x, max_y):
    " Retorna n objetos na área dada por (0, max_x, 0, max_y) "
    ret = []
    if tipo == 0:
        for i in range(n):
            ret.append(Point(randint(25, max_x - 25), randint(25, max_y - 25)))
    elif tipo == 2:
        for i in range(n):
            ret.append(
                Segment(
                    Point(randint(25, max_x - 25), randint(25, max_y - 25)),
                    Point(randint(25, max_x - 25), randint(25, max_y - 25))))
    elif tipo == 3:
        for i in range(n):
            x = randint(50, max_x - 50)
            y = randint(50, max_y - 50)
            ret.append(
                Disc(x, y, randint(5,
                                   min([x, y, max_x - x, max_y - y]) - 10)))
    elif tipo == 1:
        x = max_x / 2
        y = max_y / 2
        v = randomPolygon(x, y,
                          min(x, y) / 2, uniform(0, 1), uniform(.2, .3), n)
        ret = Polygon(v)
    return ret
Example #2
0
 def get_plot_input(self, tipo, arq):
     " Salva o objeto correspondente ao arquivo arq no self.input "
     " E desenha ele no canvas "
     self.rodei_logo = False
     f = open(tipos_input[tipo][1] + "/" + arq, "r")
     self.input = []
     self.novo_input.delete(0, END)
     self.novo_input.insert(0, arq)
     desenhos.clear()
     # Pontos
     if tipo == 0:
         for p in f:
             x, y = float(p.split()[0]), float(p.split()[1])
             self.input.append(Point(x, y))
     # Poligono
     elif tipo == 1:
         vertices = []
         for p in f:
             x, y = float(p.split()[0]), float(p.split()[1])
             vertices.append(Point(x, y))
         p = Polygon(vertices)
         self.input = p
     # Segmentos
     elif tipo == 2:
         for p in f:
             x1, y1 = float(p.split()[0]), float(p.split()[1])
             x2, y2 = float(p.split()[2]), float(p.split()[3])
             self.input.append(Segment(Point(x1, y1), Point(x2, y2)))
     # Círculos
     elif tipo == 3:
         for p in f:
             x, y, r = float(p.split()[0]), float(p.split()[1]), float(
                 p.split()[2])
             self.input.append(Disc(x, y, r))
     self.plot_input()
Example #3
0
def bentley_ottmann(l):
    L = Abbb()  # Linha de varredura
    resp = []  # Os nós com os pontos de interseção que retornaremos
    # Pré-processamento - Transforma cada circulo em pontos-eventos
    # pontos é a ABBB de pontos eventos
    pontos = eventos(l)
    desenhos.sleep()

    while not pontos.vazia():
        p = pontos.deleta_min()
        # desenha a linha
        id_linha = desenhos.plot_vert_line(p.ponto.x, 'green')
        id_evento = p.ponto.hilight('green')
        desenhos.sleep()

        "------------------------- Pontos da direita --------------------------------"
        for seg in p.fim:
            seg.ref = seg.seg.to
            deleta_da_linha(L, seg, pontos, p.ponto)

        "------------------------- Pontos da esquerda --------------------------------"
        for seg in p.ini:
            seg.seg.plot('green')
            desenhos.sleep()
            insere_na_linha(L, seg, pontos)

        "------------------------- Pontos de interseção ------------------------------"
        if len(p.inter) > 0 or (len(p.ini) + len(p.fim)) > 1:
            p.ponto.hilight('yellow')
            resp.append(p)

        # Troca a ordem dos segmentos (do p.inter[])
        trocados = []
        # Remove todos
        for seg in p.inter:
            if seg not in p.fim:
                if seg.seg.to.x != seg.seg.init.x:
                    y_ref = (((seg.seg.to.x * seg.seg.init.y) -
                              (seg.seg.init.x * seg.seg.to.y) -
                              (p.ponto.x - 10 * eps) *
                              (seg.seg.init.y - seg.seg.to.y)) /
                             (seg.seg.to.x - seg.seg.init.x))
                    seg.ref = Point(p.ponto.x - 10 * eps, y_ref)
                else:
                    seg.ref = Point(p.ponto.x, p.ponto.y + 10 * eps)
                trocados.append(seg)
                L.deleta(seg)
        # Insere denovo com o novo ponto de referencia
        for seg in trocados:
            seg.ref = p.ponto
            #print("reinserindo " + str(seg))
            insere_na_linha(L, seg, pontos, p.ponto, trocados)

        # apaga a linha
        desenhos.plot_delete(id_linha)
        desenhos.plot_delete(id_evento)
        p.ponto.unplot()

    return resp
Example #4
0
    def intersection(self, other):
        "Retorna uma lista com o(s) ponto(s) de interseção entre os dois círculos"
        if not self.intersects_circ(other):
            return []

        # Um pouco de geometria: Montando a esquação do circulo
        # Temos: self: (x - x1)^2 + (y - y1)^2 = r1^2
        #       other: (x - x2)^2 + (y - y2)^2 = r2^2
        x1, y1 = self.center.x, self.center.y
        x2, y2 = other.center.x, other.center.y
        r1, r2 = self.r, other.r

        # Depois de subtrair as duas equações, teremos uma reta
        # 2x*(x2 - x1) + 2y*(y2 - y1) + x1^2 - x2^2 + y1^2 - y2^2 = r1^2 - r2^2

        # Isolando o x para a resposta, temos essa grande conta:
        # x = [ r1^2 - r2^2 + x2^2 - x1^2 + y2^2 - x1^2 + 2y*(y2 - y1) ] / 2*(x2 - x1)

        # se x1 = x2, temos um caso mais simples, basta encontrar y
        if x1 == x2:
            if y1 == y2:
                # supondo que não há circulos iguais
                return []
            res_y1 = (r1**2 - r2**2 + y2**2 - y1**2) / (2 * (y2 - y1))
            res_y2 = res_y1
            res_x1 = (r1**2 - (res_y1 - y1)**2)**(0.5) + x1
            res_x2 = -(r1**2 - (res_y1 - y1)**2)**(0.5) + x1

        # Se não, temos que colocar o x em alguma das equações dos circulos e criar uma equação de 2º grau
        # Depois de (( muitas )) continhas ...
        # conclui que os valores de a, b e c para nossa equação ay^2 + by + c = 0 são
        else:
            const = r1**2 - r2**2 + y2**2 - y1**2 + x2**2 + x1**2 - 2 * x1 * x2

            a = (y1 - y2)**2 / (x1 - x2)**2 + 1
            b = (y1 - y2) * const / (x1 - x2)**2 - 2 * y1
            c = const**2 / (4 * (x1 - x2)**2) + y1**2 - r1**2

            # Agora a gente aplica um super bhaskara
            delta = b**2 - 4 * a * c
            res_y1 = (-b + delta**(0.5)) / (2 * a)
            res_y2 = (-b - delta**(0.5)) / (2 * a)

            # Aplica os valores na reta para descobir os x
            res_x1 = (r1**2 - r2**2 + y2**2 - y1**2 + x2**2 - x1**2 +
                      2 * res_y1 * (y1 - y2)) / (2 * (x2 - x1))
            res_x2 = (r1**2 - r2**2 + y2**2 - y1**2 + x2**2 - x1**2 +
                      2 * res_y2 * (y1 - y2)) / (2 * (x2 - x1))

        p1 = Point(res_x1, res_y1)
        p2 = Point(res_x2, res_y2)
        if p1.approx_equals(p2):
            return [p1]
        return [p1, p2]
Example #5
0
    def __init__(self, x, y, r):
        "Para criar um disco, passe suas coordenadas."
        self.center = Point(x, y)
        self.r = r
        self.seg = Segment(Point(x - r, y), Point(x + r, y))
        self.lineto_id = {}

        self.plot_id = None
        self.plot_up = None
        self.plot_down = None
        self.hi = None
Example #6
0
def pontos_infinitos (p):
    " Devolve três pontos fictícios tais que o triangulo formado por eles "
    " contém todos os pontos de p "
    
    # Vou montar um quadradão que contém todos os pontos
    cima = baixo = direito = esquerdo = p[0]
    for i in range(1, len(p)):
        if p[i].y > cima.y: cima = p[i]
        if p[i].y < baixo.y: baixo = p[i]
        if p[i].x < esquerdo.x: esquerdo = p[i]
        if p[i].x > direito.x: direito = p[i]
        
    # Agora monto um triângulão que contém esse quadrado
    p1 = Point (esquerdo.x - 10*(direito.x - esquerdo.x), baixo.y - 10*(cima.y - baixo.y))
    p2 = Point (esquerdo.x + (direito.x - esquerdo.x)/2, cima.y + 10*(cima.y - baixo.y))
    p3 = Point (esquerdo.x + 10*(direito.x - esquerdo.x), baixo.y - 10*(cima.y - baixo.y))
    return p1, p2, p3
Example #7
0
def main ():
    novo = []
    clara = []
    for i in randdisc(150, 60):
        novo.append(Point(i[0] + 300, i[1] + 392))
    for i in uniform_circ(25, 90):
        novo.append(Point(i[0] + 300, i[1] + 392))
    for i in uniform_circ(50, 110):
        novo.append(Point(i[0] + 300, i[1] + 392))
    for i in grid(15, 15):
        novo.append(Point(i[0], i[1]))
        clara.append(Point(i[0], i[1]))
        
    f = open('input/pontos/gema', "w")
    for p in novo:
        f.write ('%f %f\n' % (p.x, p.y - 92))
    f.close()
    return clara, novo
Example #8
0
def orelhas(poligono):
    """ Algoritmo que usa a estratégia de encontrar e remover orelhas para
        triangular o polígono
    """
    # Cria uma cópia pra não zoar o input original
    novo = []
    for p in poligono.vertices():
        novo.append(Point(p.x, p.y))
    P = Polygon(novo)

    n = len(P.vertices())

    # Dicionario que relaciona os vértices a um booleano que indica se é orelha
    # Aproveitando que os pontos são 'hashables'
    orelha = dict()

    #PreProcessamento dos vértices
    v = P.pts
    orelha[v] = is_orelha(v, P)
    v = v.next
    while v != P.pts:
        orelha[v] = is_orelha(v, P)
        v = v.next

    while n > 3:
        # Procura uma orelha
        while not orelha[v]:
            v = v.next

        # Sinaliza qual orelha eu escolhi
        v.hilight('firebrick')
        # Desenha a diagonal e desmarca a orelha
        v.prev.lineto(v.next, 'orange')
        orelha[v] = False
        sleep()

        # Tira v do polígono
        u = v.prev
        w = v.next
        w.prev = u
        u.next = w
        # Essa parte é pra lista sempre ficar circular
        # (P.pts podia ficar inacessivel dai o algoritmo entrava em loop)
        if v == P.pts:
            P.pts = P.pts.next

        # Confere se não criei nenhuma orelha
        orelha[u] = is_orelha(u, P)
        orelha[w] = is_orelha(w, P)

        v.unhilight()
        n -= 1

    # Despinta alguma orelha que tenha sobrado
    while not orelha[v]:
        v = v.next
    v.unhilight()
Example #9
0
def eventos(circulos):
    "Função que retorna uma ABBB de pontos-eventos, que são os extremos horizontais dos circulos"
    Q = Abbb()  # Abbb dos pontos eventos
    for c in circulos:
        p_esq = c.center - Point(c.r, 0)
        p_dir = c.center + Point(c.r, 0)
        baixo = Node_Semi_Circle(c, True, p_esq)
        cima = Node_Semi_Circle(c, False, p_esq)
        p1 = Node_Point_Circle(p_esq,
                               ini=[baixo, cima],
                               fim=[],
                               inter=[],
                               inter_unico=[])
        p2 = Node_Point_Circle(p_dir,
                               ini=[],
                               fim=[baixo, cima],
                               inter=[],
                               inter_unico=[])
        no1 = Q.busca(p1)
        no2 = Q.busca(p2)
        # Se os pontos já estão inseridos, só atualiza, se não, insere
        if no1.elemento != None:
            no1.elemento.ini.append(baixo)
            no1.elemento.ini.append(cima)
        else:
            Q.insere(p1)
            p_esq.plot('red')
            no1 = Q.busca(p1)
        if no2.elemento != None:
            no2.elemento.fim.append(baixo)
            no2.elemento.fim.append(cima)
        else:
            Q.insere(p2)
            p_dir.plot('red')

    return Q
Example #10
0
    def desenha(self):
        # Acha os dois pontos da esquerda
        x1, y1 = self.a_esq.init.x, self.a_esq.init.y
        x2, y2 = self.a_esq.to.x, self.a_esq.to.y

        # Caso degenerado
        if y1 == y2:
            s = Segment(Point(x1, y1), Point(x2, y2))
            self.aresta_cima = s
            self.aresta_baixo = s
            self.aresta_esq = s
            self.aresta_dir = s
            return

        cima = self.sup.y
        baixo = max(self.a_esq.to.y, self.a_dir.to.y)

        cima_esq = Point((x2 * y1 - x1 * y2 + cima * (x1 - x2)) / (y1 - y2),
                         cima)
        baixo_esq = Point((x2 * y1 - x1 * y2 + baixo * (x1 - x2)) / (y1 - y2),
                          baixo)

        # Acha os dois pontos da direita
        x1, y1 = self.a_dir.init.x, self.a_dir.init.y
        x2, y2 = self.a_dir.to.x, self.a_dir.to.y

        # Caso degenerado
        if y1 == y2:
            s = Segment(Point(x1, y1), Point(x2, y2))
            self.aresta_cima = s
            self.aresta_baixo = s
            self.aresta_esq = s
            self.aresta_dir = s
            return

        cima_dir = Point((x2 * y1 - x1 * y2 + cima * (x1 - x2)) / (y1 - y2),
                         cima)
        baixo_dir = Point((x2 * y1 - x1 * y2 + baixo * (x1 - x2)) / (y1 - y2),
                          baixo)

        self.aresta_cima = (Segment(cima_esq, cima_dir)).plot('orange')
        self.aresta_baixo = (Segment(baixo_esq, baixo_dir)).plot('orange')
        self.aresta_esq = (Segment(baixo_esq, cima_esq)).plot('orange')
        self.aresta_dir = (Segment(baixo_dir, cima_dir)).plot('orange')
Example #11
0
def randomPolygon(ctrX, ctrY, aveRadius, irregularity, spikeyness, numVerts):
    ''' Start with the centre of the polygon at ctrX, ctrY, 
        then creates the polygon by sampling points on a circle around the centre. 
        Randon noise is added by varying the angular spacing between sequential points,
        and by varying the radial distance of each point from the centre.
    
        Params:
        ctrX, ctrY - coordinates of the "centre" of the polygon
        aveRadius - in px, the average radius of this polygon, this roughly controls how large the polygon is, really only useful for order of magnitude.
        irregularity - [0,1] indicating how much variance there is in the angular spacing of vertices. [0,1] will map to [0, 2pi/numberOfVerts]
        spikeyness - [0,1] indicating how much variance there is in each vertex from the circle of radius aveRadius. [0,1] will map to [0, aveRadius]
        numVerts - self-explanatory
    
        Returns a list of vertices, in CCW order.
    '''

    irregularity = clip(irregularity, 0, 1) * 2 * math.pi / numVerts
    spikeyness = clip(spikeyness, 0, 1) * aveRadius

    # generate n angle steps
    angleSteps = []
    lower = (2 * math.pi / numVerts) - irregularity
    upper = (2 * math.pi / numVerts) + irregularity
    sum = 0
    for i in range(numVerts):
        tmp = uniform(lower, upper)
        angleSteps.append(tmp)
        sum = sum + tmp

    # normalize the steps so that point 0 and point n+1 are the same
    k = sum / (2 * math.pi)
    for i in range(numVerts):
        angleSteps[i] = angleSteps[i] / k

    # now generate the points
    points = []
    angle = uniform(0, 2 * math.pi)
    for i in range(numVerts):
        r_i = clip(gauss(aveRadius, spikeyness), 0, 2 * aveRadius)
        x = ctrX + r_i * math.cos(angle)
        y = ctrY + r_i * math.sin(angle)
        points.append(Point(int(x), int(y)))

        angle = angle + angleSteps[i]

    return points
Example #12
0
    def intersection(self, other_segment):
        "Retorna o ponto de interseção entre as duas retas se existir"
        if not self.intersects(other_segment):
            return None
        # um pouco de geometria, montando e igualando as equações das retas
        x0, y0 = self.init.x, self.init.y
        x1, y1 = self.to.x, self.to.y
        x2, y2 = other_segment.init.x, other_segment.init.y
        x3, y3 = other_segment.to.x, other_segment.to.y

        # r1 : a1x + b1y = c1
        a1 = y0 - y1
        b1 = x1 - x0
        c1 = x0 * y1 - x1 * y0
        # r2: a2x + b2y = c2
        a2 = y2 - y3
        b2 = x3 - x2
        c2 = x2 * y3 - x3 * y2
        # Resposta do sistema linear
        x = (b1 * c2 - b2 * c1) / (a1 * b2 - a2 * b1)
        y = (a2 * c1 - a1 * c2) / (a1 * b2 - a2 * b1)
        return Point(x, y)
Example #13
0
def lee_preparata(poligono):

    # Cria uma cópia pra não zoar o input original
    novo = []
    for p in poligono.vertices():
        novo.append(Point(p.x, p.y))
    P = Polygon(novo)

    diags = []
    d = Dcel()
    d.init_polygon(P)

    # Atualiza a DCEL colocando as diagonais parar a partição em monótonos
    monotonos(d, P, diags)
    n_face_externa = len(P.vertices())
    divisoras = len(diags)
    # Para cada face, constrói um polígono e triangula ele

    if len(d.f) == 2:
        return monotono(P)

    for e in d.f:
        vertices = [e.init]
        while e.to != vertices[0]:
            vertices.append(e.to)
            e = e.prox
        if len(vertices) != n_face_externa:
            new_p = Polygon(vertices)
            new_p.plot('green')
            desenhos.sleep()
            # Triangula o new_p e adiciona as novas diagonais no diags
            diags.extend(monotono(new_p))
            new_p.hide()

    # despinta as arestas
    for i in range(divisoras):
        diags[i].hide()
        diags[i].plot("orange")
Example #14
0
    def __gt__(self, other):
        if self.circ == other.circ:
            return self.baixo and not other.baixo
        ref = other.ref
        x = self.circ.center.x
        y = self.circ.center.y

        # Se o ponto de referencia é uma interseção,
        if abs((ref.x - x)**2 + (ref.y - y)**2 - self.circ.r**2) < eps:
            # então eu pego um ponto um pouco posterior pra ser o ponto de refencia,
            # aplicando a formula do circulo pra 2*epsilon pra frente
            if other.baixo:
                sinal = -1
            else:
                sinal = 1
            # Formula do circulo
            x_novo = ref.x + 2 * eps
            x_novo = min(x_novo, other.circ.center.x + other.circ.r)
            y_novo = other.circ.center.y
            y_novo += sinal * (other.circ.r**2 -
                               (x_novo - other.circ.center.x)**2)**0.5
            ref = Point(x_novo, y_novo)
        # Self > other <=> other está a esquerda do self
        return self.esquerda(ref, other.baixo)
Example #15
0
    def extremes(self):

        offsets = [self.r, -self.r]

        return [self.center + Point(0, off) for off in offsets
                ] + [self.center + Point(off, 0) for off in offsets]
Example #16
0
def escreve_algorithms():
    a = [Point (315, 50), Point (319, 60), Point (331, 60), Point (319, 60), 
         Point (323, 70), Point (327, 70), Point (335, 50)]
    for i in range(1, len(a)):
        a[i].lineto(a[i - 1], 'orange')
        sleep()
    l = [Point (339, 66), Point (339, 50), Point (352, 50)]
    for i in range(1, len(l)):
        l[i].lineto(l[i - 1], 'orange')
        sleep()
    g = [Point (370, 66), Point (356, 66), Point (356, 50), Point (370, 50),
         Point (370, 58), Point (364, 58)]
    for i in range(1, len(g)):
        g[i].lineto(g[i - 1], 'orange')
        sleep()
    o = [Point (374, 50), Point (374, 66), Point (387, 66), Point (387, 50)]
    for i in range(len(o)):
        o[i].lineto(o[i - 1], 'orange')
        sleep()
    r = [Point (392, 50), Point (392, 66), Point (408, 66), Point (408, 58), 
         Point (398, 58), Point (408, 50)]
    for i in range(1, len(r)):
        r[i].lineto(r[i - 1], 'orange')
        sleep()
    i = [Point (413, 50), Point (426, 50), Point (419, 50), 
         Point (419, 66), Point (426, 66), Point (413, 66)]
    for j in range(1, len(i)):
        i[j].lineto(i[j - 1], 'orange')
        sleep()
    t = [Point (438, 50), Point (438, 66), Point (430, 66), Point (446, 66)]
    for i in range(1, len(t)):
        t[i].lineto(t[i - 1], 'orange')
        sleep()
    h = [Point (451, 50), Point (451, 66), Point(451, 58), 
         Point (465, 58), Point (465, 50), Point (465, 66)]
    for i in range(1, len(h)):
        h[i].lineto(h[i - 1], 'orange')
        sleep()
    m = [Point (470, 50), Point (470, 66), Point (478, 58), Point (486, 66), Point(486, 50)]
    for i in range(1, len(m)):
        m[i].lineto(m[i - 1], 'orange')
        sleep()
    s = [Point (507, 66), Point (491, 66), Point (491, 58),
         Point (507, 58), Point (507, 50), Point (491, 50)]
    for i in range(1, len(s)):
        s[i].lineto(s[i - 1], 'orange')
        sleep()
Example #17
0
def escreve_geometric():
    g = [Point (130, 70), Point (110, 70), Point (110, 50), Point (130, 50),
         Point (130, 60), Point (120, 60)]
    for i in range(1, len(g)):
        g[i].lineto(g[i - 1], 'orange')
        sleep()
    e = [Point (151, 50), Point (135, 50), Point (135, 58), Point (151, 58), 
         Point (135, 58), Point (135, 66), Point (151, 66)]
    for i in range(1, len(e)):
        e[i].lineto(e[i - 1], 'orange')
        sleep()
    o = [Point (156, 50), Point (156, 66), Point (172, 66), Point (172, 50)]
    for i in range(len(o)):
        o[i].lineto(o[i - 1], 'orange')
        sleep()
    m = [Point (177, 50), Point (177, 66), Point (185, 58), Point (193, 66), Point(193, 50)]
    for i in range(1, len(m)):
        m[i].lineto(m[i - 1], 'orange')
        sleep()
    e = [Point (214, 50), Point (198, 50), Point (198, 58), Point (214, 58), 
         Point (198, 58), Point (198, 66), Point (214, 66)]
    for i in range(1, len(e)):
        e[i].lineto(e[i - 1], 'orange')
        sleep()
    t = [Point (224, 50), Point (224, 66), Point (216, 66), Point (231, 66)]
    for i in range(1, len(t)):
        t[i].lineto(t[i - 1], 'orange')
        sleep()
    r = [Point (233, 50), Point (233, 66), Point (247, 66), Point (247, 58), 
         Point (237, 58), Point (247, 50)]
    for i in range(1, len(r)):
        r[i].lineto(r[i - 1], 'orange')
        sleep()
    i = [Point (252, 50), Point (264, 50), Point (258, 50), 
         Point (258, 66), Point (252, 66), Point (264, 66)]
    for j in range(1, len(i)):
        i[j].lineto(i[j - 1], 'orange')
        sleep()
    c = [Point (285, 50), Point (269, 50), Point (269, 66), Point (285, 66)]
    for i in range(1, len(c)):
        c[i].lineto(c[i - 1], 'orange')
        sleep()
Example #18
0
def escreve_gema():
    g = [Point (210, 190), Point (140, 190), Point (140, 110), Point (210, 110),
         Point (210, 150), Point (190, 150)]
    for i in range(len(g)):
        g[i].hilight()
        if (i > 0):
            g[i].lineto(g[i - 1], 'orange')
        sleep()
    e = [Point (290, 110), Point (230, 110), Point (230, 150), Point (290, 150), 
         Point (230, 150), Point (230, 180), Point (290, 180)]
    for i in range(len(e)):
        e[i].hilight()
        if (i > 0):
            e[i].lineto(e[i - 1], 'orange')
        sleep()
        
    m = [Point (310, 110), Point (310, 180), Point (340, 150), Point (370, 180), Point(370, 110)]
    for i in range(len(m)):
        m[i].hilight()
        if (i > 0):
            m[i].lineto(m[i - 1], 'orange')
        sleep()
        
    a = [Point (390, 110), Point (405, 150), Point (445, 150), Point (405, 150), 
         Point (420, 190), Point (430, 190), Point (460, 110)]
    for i in range(len(a)):
        a[i].hilight()
        if (i > 0):
            a[i].lineto(a[i - 1], 'orange')
        sleep()
Example #19
0
def varre(l):
    "Algoritmo de divisão e conquista para encontrar o par de pontos mais proximo"
    "Recebe uma lista de pontos l"

    if len(l) < 2: return None

    d = float('inf')

    l = sorted(l, key=lambda x: x.x)

    par_min = None
    faixa = Abbb()

    p_min = 0

    for i in range(len(l)):
        p = l[i]
        no_p = Node_point(p)

        # Caso degenerado -> pontos coincidentes
        # (não conseguimos adicionar na abbb, pois ja tem um clone dele)
        repetido = faixa.busca(no_p).elemento
        if repetido != None:
            if par_min != None:
                par_min.hide()
            par_min = Segment(p, repetido.p)
            break

        faixa.insere(no_p)
        p.hilight()

        # Remove os pontos fora da faixa
        while p.x - l[p_min].x > d:
            l[p_min].unhilight()
            if l[p_min] in par_min.endpoints():
                l[p_min].hilight('orange')
            no_p_min = Node_point(l[p_min])
            faixa.deleta(no_p_min)
            p_min += 1

        # Desenha o quadradinho de candidatos
        linha_frente = desenhos.plot_vert_line(p.x, 'orange')
        if i > 1:
            linha_tras = desenhos.plot_vert_line(p.x - d, cor='firebrick')
            linha_cima = Segment(Point(p.x, p.y + d), Point(p.x - d, p.y + d))
            linha_baixo = Segment(Point(p.x, p.y - d), Point(p.x - d, p.y - d))
            linha_cima.plot('firebrick')
            linha_baixo.plot('firebrick')
        desenhos.sleep()

        # Extrai os pontos da abbb até a distancia vertical ficar maior que d
        # Primeiro com os vizinhos de cima
        vizinho = faixa.sucessor(no_p)
        while vizinho != None and vizinho.p.y - p.y < d:
            d2 = dist2(p, vizinho.p)
            p.hilight()
            vizinho.p.hilight('firebrick')
            if d2 < d * d:
                d = d2**0.5

                if par_min is not None:
                    par_min.unhilight()
                par_min = Segment(p, vizinho.p)
                par_min.hilight('orange')
                desenhos.sleep()

            vizinho = faixa.sucessor(vizinho)
        # Depois com os vizinhos de baixo
        vizinho = faixa.predecessor(no_p)
        while vizinho is not None and p.y - vizinho.p.y < d:
            d2 = dist2(p, vizinho.p)
            p.hilight()
            vizinho.p.hilight('firebrick')
            if d2 < d * d:
                d = d2**0.5

                if par_min is not None:
                    par_min.unhilight()
                par_min = Segment(p, vizinho.p)
                par_min.hilight('orange')
                desenhos.sleep()

            vizinho = faixa.predecessor(vizinho)

        # Apaga o quadradinho
        desenhos.plot_delete(linha_frente)
        if (i > 1):
            desenhos.plot_delete(linha_tras)
            linha_cima.hide()
            linha_baixo.hide()

        p.unhilight()
        l[i].hilight('firebrick')

    "despinta quem sobrou na faixa"
    while (not faixa.vazia()):
        faixa.deleta_min().p.unhilight()
    par_min.hilight('orange')