def ilegal(e): " Devolve se a aresta dada pela meia aresta 'e' é ilegal " # As arestas do triangulão infinito não podem ser ilegais global infs if e.init in infs and e.to in infs: return False e.draw(color_legalizaveis) sleep() # O quadrilatero precisa ser convexo if left(e.twin.prox.to, e.to, e.prox.to) == left(e.twin.prox.to, e.init, e.prox.to): return False def angulo(p1, p2, p3): " Devolve algo proporcional ao angulo em p2 de p1-p2-p3 " # Na verdade, devolve o -2*cosseno do angulo com a lei do cosseno a2 = (p3.x - p1.x)**2 + (p3.y - p1.y)**2 b2 = (p3.x - p2.x)**2 + (p3.y - p2.y)**2 c2 = (p1.x - p2.x)**2 + (p1.y - p2.y)**2 ang = ((b2 + c2 - a2) / (2 * ((b2 * c2)**0.5))) return -ang # Como cosseno é descrescente para angulos menores que pi, # Então posso comparar dois angulos a e b pelos seus cossenos # a > b <=> cos(a) < cos(b) # Acha o menor angulo do triangulo com a aresta e min_ang1 = min([ angulo(e.prev.init, e.init, e.to), angulo(e.init, e.to, e.prev.init), angulo(e.to, e.prev.init, e.init) ]) # Acha o menor angulo do triangulo com a aresta e.twin min_ang2 = min([ angulo(e.twin.prev.init, e.init, e.to), angulo(e.init, e.to, e.twin.prev.init), angulo(e.init, e.twin.prev.init, e.to) ]) min_ang_legal = min(min_ang1, min_ang2) # Acha o menor angulo dos triangulos com a outra diagonal min_ang1 = min([ angulo(e.prev.init, e.init, e.twin.prev.init), angulo(e.init, e.prev.init, e.twin.prev.init), angulo(e.prev.init, e.twin.prev.init, e.init) ]) min_ang2 = min([ angulo(e.prev.init, e.to, e.twin.prev.init), angulo(e.to, e.prev.init, e.twin.prev.init), angulo(e.prev.init, e.twin.prev.init, e.to) ]) min_ang_ilegal = min(min_ang1, min_ang2) return min_ang_legal < min_ang_ilegal
def intersects_inside(self, other_segment) -> bool: ''' returns whether the other segment intersects this segment (not counting border points) ''' if self.colinear_with(other_segment.init) \ or self.colinear_with(other_segment.to) \ or other_segment.colinear_with(self.init) \ or other_segment.colinear_with(self.to): return False return (left(self.init, self.to, other_segment.init) ^ left(self.init, self.to, other_segment.to)) \ and (left(other_segment.init, other_segment.to, self.init) ^ left(other_segment.init, other_segment.to, self.to))
def trata_ponta_pra_cima(p, L, dcel, diags): viz_esq = p.next viz_dir = p.prev if left(p, viz_dir, viz_esq): viz_esq, viz_dir = viz_dir, viz_esq t = Trapezio(p) removido = (L.busca(t)).elemento if removido == None: t.a_esq = Segment(p, viz_esq) t.a_dir = Segment(p, viz_dir) t.desenha() L.insere(t) else: L.deleta(t) removido.apaga() d = Segment(p, removido.sup) d.plot('firebrick') dcel.add_edge(d.init, d.to) diags.append(d) desenhos.sleep() t1 = Trapezio(p, removido.a_esq, Segment(p, viz_esq)) t2 = Trapezio(p, Segment(p, viz_dir), removido.a_dir) t1.desenha() t2.desenha() L.insere(t1) L.insere(t2) desenhos.sleep()
def __gt__(self, other): ref = other.ref # Se o ponto de referencia é uma interseção, if abs(area2(self.seg.init, self.seg.to, ref)) < eps: # O ponto de referência vai ser o ponto da direita ref = other.seg.to # Self > other <=> other está a esquerda do self return left(self.seg.init, self.seg.to, ref)
def tangente_superior(h_esq, h_dir): """ Encontra os pontos i, j tais que a linha h_esq[i] - h_dir[j] deixa todos os demais pontos abaixo 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_dir[j].remove_lineto(h_esq[i]) h_dir[j].lineto(h_esq[i], 'blue') sleep() prox_i = (i + 1) % n_esq prox_j = (j - 1 + n_dir) % n_dir subiu = True while subiu: subiu = False while (left(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]))): subiu = True h_dir[j].remove_lineto(h_esq[i]) i = prox_i prox_i = (i + 1) % n_esq h_dir[j].lineto(h_esq[i], 'blue') sleep() while (left(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]))): subiu = True h_dir[j].remove_lineto(h_esq[i]) j = prox_j prox_j = (j - 1 + n_dir) % n_dir h_dir[j].lineto(h_esq[i], 'blue') sleep() h_dir[j].remove_lineto(h_esq[i]) h_dir[j].lineto(h_esq[i], 'firebrick') sleep() return i, j
def dentro_do_poligono(u, w, P): """ Função que recebe dois vértices u e w do polígono P e retorna se a candidata a diagonal uw está pra dentro do polígono (equivalente a função NoCone dos slides) """ prevU = u.prev nextU = u.next if (left_on(prevU, u, nextU)): resposta = (left(u, w, prevU) and left(w, u, nextU)) else: resposta = not (left_on(u, w, nextU) and left_on(w, u, prevU)) if not resposta: uw = Segment(u, w) uw.plot('red') sleep() uw.hide() return resposta
def __init__ (self, p1, p2, p3, a): if left (p1, p2, p3): self.p1 = p1 self.p2 = p2 else: self.p1 = p2 self.p2 = p1 self.p3 = p3 self.a = a # Alguma aresta da DCEL que faz parte desse triangulo self.filhos = [] # Node_Triangs que são filhos do self no DAG # arestas self.a1 = Segment (self.p1, self.p2) self.a2 = Segment (self.p2, self.p3) self.a3 = Segment (self.p3, self.p1)
def quickhull_rec(P, l, r): """ Função principal do algoritmo """ if r - l == 1: P[l].hilight() P[r].hilight() P[l].lineto(P[r], "orange") sleep() return [P[r], P[l]] # P[l + 1] recebe ponto extremo for i in range(l + 1, r): P[i].lineto(P[l], "gray") P[i].lineto(P[r], "gray") sleep() P[i].remove_lineto(P[l]) P[i].remove_lineto(P[r]) if (abs(area2(P[i], P[l], P[r])) > abs(area2(P[l + 1], P[l], P[r])) or (abs( abs(area2(P[i], P[l], P[r])) - abs(area2(P[l + 1], P[l], P[r]))) < eps and left(P[l], P[l + 1], P[i]))): P[i], P[l + 1] = P[l + 1], P[i] # caso degenerado: pontos colineares if abs(area2(P[l], P[l + 1], P[r])) < eps: P[l].hilight() P[r].hilight() P[l].lineto(P[r], "orange") sleep() return [P[r], P[l]] p, q, linha_esq, linha_dir = particione(P, l, r) P[p].unhilight() P[q].unhilight() P[p].hilight("green") P[q].hilight("red") sleep() fecho_esq = quickhull_rec(P, p, q) fecho_dir = quickhull_rec(P, q, r) plot_delete(linha_esq) plot_delete(linha_dir) sleep() for e in range(1, len(fecho_esq)): fecho_dir.append(fecho_esq[e]) return fecho_dir
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 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)
def __gt__(self, other): return left(self.a_esq.init, self.a_dir.to, other.sup)
def has_left(self, point): return left(self.init, self.to, point)