def edges(self): edges = [] p = self.pts while p.next != self.pts: edges.append(Segment(p, p.next)) p = p.next edges.append(Segment(p, p.next)) return edges
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 trata_ponta_pra_baixo(p, L, dcel, diags): t = Trapezio(p) removido1 = (L.busca(t)).elemento removido1.apaga() L.deleta(t) if ponta_pra_baixo(removido1.sup): d = Segment(removido1.sup, p) d.plot('firebrick') desenhos.sleep() dcel.add_edge(d.init, d.to) diags.append(d) # Se tem outro polígono removido2 = (L.busca(t)).elemento if removido2 != None: L.deleta(t) removido2.apaga() if ponta_pra_baixo(removido2.sup): d = Segment(removido2.sup, p) d.plot('firebrick') desenhos.sleep() dcel.add_edge(d.init, d.to) diags.append(d) if removido2.a_esq.to == p: t = Trapezio(p, removido1.a_esq, removido2.a_dir) else: t = Trapezio(p, removido2.a_esq, removido1.a_dir) L.insere(t) t.desenha() desenhos.sleep()
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 forca_bruta(l): "Algoritmo forca bruta para encontrar o par de pontos mais proximo" "Recebe uma lista de pontos l" if len(l) < 2: return None closest = float("inf") a = b = None for i in range(len(l)): for j in range(i + 1, len(l)): l[i].lineto(l[j], 'firebrick') sleep() l[i].remove_lineto(l[j]) dist = dist2(l[i], l[j]) if dist < closest: if a is not None: a.unhilight() b.unhilight() a.remove_lineto(b) closest = dist a = l[i] b = l[j] a.hilight("orange") b.hilight("orange") a.lineto(b, "orange") sleep() ret = Segment(a, b) return ret
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
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()
def intersecta_borda(u, w, P): """ Função que recebe dois vértices u e w do polígono P e retorna se o segmento uw intersecta alguma aresta de P (equivalente a função QuaseDiagonal dos slides) """ borda = P.edges() uw = Segment(u, w) for aresta in borda: aresta.plot('green') sleep() if (u not in aresta.endpoints()) and (w not in aresta.endpoints()): if (uw.intersects(aresta)): aresta.hide() aresta.plot('red') sleep() aresta.hide() return True aresta.hide() return False
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
def trata_caso_meio(p, viz_baixo, L, dcel, diags): # Remove da linha o trapésio que tem o p t = Trapezio(p) removido = (L.busca(t)).elemento removido.apaga() L.deleta(t) if ponta_pra_baixo(removido.sup): d = Segment(removido.sup, p) d.plot('firebrick') dcel.add_edge(d.init, d.to) diags.append(d) desenhos.sleep() # Insere um novo trapésio com o p # Se o removido estava a direita if (p == removido.a_dir.to): t.a_dir = Segment(p, viz_baixo) t.a_esq = removido.a_esq # Se estava a esquerda else: t.a_esq = Segment(p, viz_baixo) t.a_dir = removido.a_dir t.desenha() L.insere(t) desenhos.sleep()
def ShamosRec(l, i, j): " Função que faz o serviço recursivo " " recebe uma lista de pontos l[i:j] ordenados pela coordenada x " # Base da recursão, 2 ou 1 ponto if j - i < 3: # registra o par mais proximo par_min = Segment(l[i], l[j - 1]) par_min.hilight('green') desenhos.sleep() # Ordena pelo eixo y if (l[i].y > l[j - 1].y): l[i], l[j - 1] = l[j - 1], l[i] else: q = (i + j) // 2 meio = l[q] vert_id = desenhos.plot_vert_line(meio.x, 'firebrick', grossura=1) meio.hilight('firebrick') desenhos.sleep() # Calcula o menor das duas metades par_esq = ShamosRec(l, i, q) par_dir = ShamosRec(l, q, j) desenhos.plot_delete(vert_id) meio.unhilight() par_min = minPar(par_esq, par_dir) par_esq.unhilight() par_dir.unhilight() par_esq.hilight('red') par_dir.hilight('red') desenhos.sleep() par_esq.unhilight() par_dir.unhilight() par_min.hilight('orange') desenhos.sleep() # Intercala do mergeSort escondido intercalaY(l, i, j) # Calcula o menor entre as duas metade par_inter = menorInter(l, i, j, meio, par_min) if par_inter != None: par_min = minPar(par_inter, par_min) par_inter.hide() global d dnovo = math.sqrt(dist(par_min)) d = min(d, dnovo) return par_min
def is_diagonal(u, w, P): """ Função que recebe dois vértices u e w do polígono P e retorna se uw é uma diagonal de P """ # colore a candidata a diagonal uw = Segment(u, w) uw.plot('green') sleep() # Como o dentroDoPoligono é O(1) é muito prudente fazer esse teste primeiro result = dentro_do_poligono(u, w, P) and (not intersecta_borda(u, w, P)) uw.hide() return result
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')
def menorInter(l, i, j, meio, par_min): " Retorna o par de pontos mais proximo dentro da faixa dada pelo ponto meio da lista " " e a distancia do par_min " d = math.sqrt(dist(par_min)) # desenha a faixa que eu estou procurando v1 = desenhos.plot_vert_line(meio.x - d, 'orange', grossura=1) v2 = desenhos.plot_vert_line(meio.x + d, 'orange', grossura=1) cand = candidatos(l, i, j, meio) par_inter = None for k in range(len(cand)): cand[k].plot('red') desenhos.sleep() for l in range(k + 1, len(cand)): # Se os pontos já estão distantes, posso parar de olhar if (cand[l].y - cand[k].y > d): break cand_inter = Segment(cand[k], cand[l]) cand_inter.plot('red') desenhos.sleep() cand_inter.hide() dcand = math.sqrt(dist2(cand[k], cand[l])) # Se achei um novo par, apaga o outro e pinta esse if (dcand < d): d = dcand if par_inter is not None: par_inter.unhilight() par_min.unhilight() par_inter = cand_inter par_inter.hilight('orange') desenhos.sleep() cand[k].unplot() desenhos.plot_delete(v1) desenhos.plot_delete(v2) desenhos.sleep() return par_inter
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 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')
class Node_Triang: " Classe que será o nó do DAG, guarda os triângulos que fazem parte da triangulação " 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 draw (self): self.a1.plot("gray") self.a2.plot("gray") self.a3.plot("gray") sleep() def hide (self): self.a1.hide() self.a2.hide() self.a3.hide() def busca (self, ponto): " Retorna o nó folha em que o ponto está " if desenha_busca: self.draw() for f in self.filhos: if (left_on (f.p1, f.p2, ponto) and left_on (f.p2, f.p3, ponto) and left_on (f.p3, f.p1, ponto)): if desenha_busca: self.hide() return f.busca (ponto) if desenha_busca: self.hide() return self
def monotono(P): # lista com as diagonais, nosso return resp = [] v = ordenaY(P) n = len(v) s = [v[0], v[1]] # pilha v[0].hilight('firebrick') v[1].hilight('firebrick') t = 1 # index do fim da pilha if v[1] == v[0].next: borda = 1 else: borda = 0 for i in range(2, n): v[i].hilight('orange') sleep() vizinho_ultimo = adj(v[i], s[t]) vizinho_primeiro = adj(v[i], s[0]) if vizinho_ultimo and not vizinho_primeiro: while t > 0 and convexo(v[i], s[t], s[t - 1], borda): s[t].unhilight() s.pop() t -= 1 # acrescenta a nova diagonal d = Segment(s[t], v[i]) d.plot('orange') sleep() resp.append(d) t += 1 s.append(v[i]) v[i].unhilight() v[i].hilight('firebrick') elif vizinho_primeiro and not vizinho_ultimo: borda = 1 - borda aux = s[t] while t > 0: # acrescenta a nova diagonal d = Segment(s[t], v[i]) d.plot('orange') sleep() resp.append(d) s.pop() t -= 1 s[t].unhilight() s = [] s.append(aux) s.append(v[i]) v[i].unhilight() v[i].hilight('firebrick') t = 1 else: while t > 1: s[t].unhilight() t -= 1 # acrescenta a nova diagonal d = Segment(s[t], v[i]) d.plot('orange') sleep() resp.append(d) s[0].unhilight() s[1].unhilight() v[i].unhilight() return resp