def embrulho(P): """ Função principal do algoritmo """ p_esq = P[0] for p in P: if p.x < p_esq.x or (p.x == p_esq.x and p.y < p_esq.y): p_esq = p p_esq.hilight('orange') sleep() H = [p_esq] while True: if P[0] == H[-1]: p_i = P[1] else: p_i = P[0] p_i.hilight('firebrick') H[-1].lineto(p_i, 'firebrick') sleep() for p_j in P: if p_j == H[-1] or p_j == p_i: continue H[-1].lineto(p_j, 'gray') sleep() H[-1].remove_lineto(p_j) if (right(H[-1], p_i, p_j) or (collinear(H[-1], p_i, p_j) and dist2(H[-1], p_i) < dist2(H[-1], p_j))): H[-1].remove_lineto(p_i) p_i.unhilight() if p_i in H: p_i.hilight('orange') p_i = p_j H[-1].lineto(p_i, 'firebrick') p_i.hilight('firebrick') H[-1].lineto(p_i, 'orange') p_i.hilight('orange') if p_i == H[0]: break H.append(p_i) return H
def tangente_inferior(h_esq, h_dir): """ Encontra os pontos i, j tais que a linha h_esq[i] - h_dir[j] deixa todos os demais pontos acima dela """ n_esq = len(h_esq) n_dir = len(h_dir) i = j = 0 for k in range(len(h_esq)): if h_esq[k].x > h_esq[i].x or (h_esq[k].x == h_esq[i].x and h_esq[k].y > h_esq[i].y): i = k for k in range(len(h_dir)): if h_dir[k].x < h_dir[j].x or (h_dir[k].x == h_dir[j].x and h_dir[k].y < h_dir[j].y): j = k h_esq[i].remove_lineto(h_dir[j]) h_esq[i].lineto(h_dir[j], 'blue') sleep() prox_i = (i - 1 + n_esq) % n_esq prox_j = (j + 1) % n_dir desceu = True while desceu: desceu = False while (right(h_esq[i], h_dir[j], h_esq[prox_i]) or (collinear(h_esq[i], h_dir[j], h_esq[prox_i]) and dist2(h_esq[i], h_dir[j]) < dist2(h_esq[prox_i], h_dir[j]))): desceu = True h_esq[i].remove_lineto(h_dir[j]) i = prox_i prox_i = (i - 1 + n_esq) % n_esq h_esq[i].lineto(h_dir[j], 'blue') sleep() while (right(h_esq[i], h_dir[j], h_dir[prox_j]) or (collinear(h_esq[i], h_dir[j], h_dir[prox_j]) and dist2(h_dir[j], h_esq[i]) < dist2(h_dir[prox_j], h_esq[i]))): desceu = True h_esq[i].remove_lineto(h_dir[j]) j = prox_j prox_j = (j + 1) % n_dir h_esq[i].lineto(h_dir[j], 'blue') sleep() h_esq[i].remove_lineto(h_dir[j]) h_esq[i].lineto(h_dir[j], 'firebrick') sleep() return i, j
def angulo(v3): " Devolve algo proporcional ao angulo em v2 de v1-v2-v3 " # Vou achar, na verdade, o cosseno do angulo com a lei do cosseno a2 = (v3.x - v1.x)**2 + (v3.y - v1.y)**2 b2 = (v3.x - v2.x)**2 + (v3.y - v2.y)**2 c2 = (v1.x - v2.x)**2 + (v1.y - v2.y)**2 ang = ((b2 + c2 - a2) / (2 * ((b2 * c2)**0.5))) if right(v1, v2, v3): ang = -ang - 1000 return -ang
def compara (p_min, p1, p2): " Comparação angular para pré-processamento dos pontos " p_min.lineto(p1, 'gray') p_min.lineto(p2, 'gray') p1.lineto(p2, 'gray') sleep() p_min.remove_lineto(p1) p_min.remove_lineto(p2) p1.remove_lineto(p2) if (right(p_min, p1, p2) or (abs(area2(p_min, p1, p2)) < eps and dist2(p_min, p1) < dist2(p_min, p2))): return 1 return 0
def quickhull(P): if len(P) <= 1: return P # Ponto mais baixo for i in range(len(P)): if P[i].y < P[0].y or (P[i].y == P[0].y and P[i].x > P[0].x): P[0], P[i] = P[i], P[0] # Ponto mais a direita do ponto mais baixo for i in range(len(P)): if (right(P[0], P[-1], P[i]) or (abs( area2(P[0], P[-1], P[i]) < eps and dist2(P[0], P[-1]) < dist2(P[0], P[i])))): P[-1], P[i] = P[i], P[-1] P[0].hilight("green") P[-1].hilight("red") P[0].lineto(P[-1], "orange") sleep() return quickhull_rec(P, 0, len(P) - 1)
def particione(P, l, r): """ Particiona o conjunto de pontos P em 3 partes: A esquerda do triangulo l-r-x A direita do triangulo l-r-x Dentro do triangulo l-r-x, onde x é o ponto em P que maximiza a área do triangulo """ # Desenha o triangulo if hasattr(P[l + 1], 'hi'): P[l + 1].unhilight() P[l + 1].hilight("firebrick") linha_esq = P[l].lineto(P[l + 1], "green") linha_dir = P[r].lineto(P[l + 1], "red") sleep() p = q = r for k in range(r - 1, l + 1, -1): if hasattr(P[k], 'hi'): P[k].unhilight() P[k].hilight("yellow") sleep() P[k].unhilight() if left(P[l], P[l + 1], P[k]): # ponto da partição esquerda (verde) p -= 1 P[p], P[k] = P[k], P[p] P[p].hilight("green") sleep() elif right(P[r], P[l + 1], P[k]): # ponto da partição direita (vermelho) p -= 1 q -= 1 P[q], P[k] = P[k], P[q] if p != q: P[p], P[k] = P[k], P[p] P[q].hilight("red") sleep() # Ajustes finais no vetor p -= 1 q -= 1 P[q], P[l + 1] = P[l + 1], P[q] if p != q: P[p], P[l + 1] = P[l + 1], P[p] p -= 1 P[l], P[p] = P[p], P[l] return p, q, linha_esq, linha_dir
def graham (P): """ Função principal do algooritmo """ P = pre_processa(P) if len(P) < 3: return P P[1].hilight('orange') P[0].lineto(P[1], 'orange') P[2].hilight('orange') P[1].lineto(P[2], 'orange') sleep() H = P[:3] for p in P[3:]: p.hilight ('orange') H[-1].lineto (p, 'orange') sleep() while (right (H[-2], H[-1], p) or (abs(area2(H[-2], H[-1], p)) < eps and dist2(H[-2], H[-1]) < dist2(H[-2], p))): H[-1].hilight ('firebrick') H[-2].remove_lineto (H[-1]) H[-1].remove_lineto (p) H[-2].lineto (H[-1], 'firebrick') H[-1].lineto (p, 'firebrick') sleep() H[-1].unhilight() H[-2].remove_lineto (H[-1]) H[-1].remove_lineto (p) H.pop() H[-1].lineto (p, 'orange') sleep() H.append(p) if collinear (H[-2], H[-1], H[0]): H[-2].remove_lineto(H[-1]) H[-1].unhilight() H.pop() H[-1].lineto (H[0], 'orange') return H
def convexo(a, b, c, borda): " Decide se o ângulo em b é convexo no polígono " # Caso borda direita if borda == 0: return left(a, b, c) # Caso borda esquerda return right(a, b, c)