def monotonos(d, P, diags): """ Função que recebe um polígono P e particiona P em vários polígonos monótonos Através da inserção de diagonais Coloca as diagonais na DCEL d """ # Ordena os vértices pela Y-coordenada v = P.vertices() v = sorted(v, key=lambda x: (-x.y * 10000 + x.x)) L = Abbb() # os vértices são os pontos eventos da linha de varredura for p in v: p.hilight() h = desenhos.plot_horiz_line(p.y, 'green') desenhos.sleep() viz_cima = p.next viz_baixo = p.prev if viz_cima.y < viz_baixo.y: viz_cima, viz_baixo = viz_baixo, viz_cima if ((viz_cima.y > p.y and p.y > viz_baixo.y) or (viz_cima.y == p.y and viz_cima.x < p.x) or (viz_baixo.y == p.y and viz_baixo.x > p.x)): trata_caso_meio(p, viz_baixo, L, d, diags) elif viz_cima.y <= p.y: trata_ponta_pra_cima(p, L, d, diags) else: trata_ponta_pra_baixo(p, L, d, diags) desenhos.plot_delete(h) p.unhilight()
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
def hilight(self, cor=desenhos.cor_destaque): "Desenha o ponto com 'destaque' (raio maior e cor diferente)" if self.hi != None: desenhos.plot_delete(self.hi) self.hi = desenhos.plot_point(self.x, self.y, cor, r=desenhos.raio_ponto_destaque) return self.hi
def hide(self): "Apaga o poligono na tela" p = self.pts while p.next != self.pts: if p in self.cid: desenhos.plot_delete(self.cid[p]) del (self.cid[p]) p = p.next if p in self.cid: desenhos.plot_delete(self.cid[p]) del (self.cid[p])
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 bentley_ottmann_mod(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 arco in p.fim: deleta_da_linha(L, arco, pontos, p.ponto.x) "------------------------- Pontos da esquerda --------------------------------" for arco in p.ini: insere_na_linha(L, arco, pontos) "------------------------- Pontos de interseção ------------------------------" if len(p.inter) > 0 or len( p.inter_unico) > 0 or (len(p.ini) + len(p.fim) >= 4): p.ponto.hilight('yellow') resp.append(p) # Troca a ordem dos arcos (do p.inter[]) # (Não troco a ordem do p.inter_unico[] porque os circulos não se "penetram") trocados = [] # Remove todos for arco in p.inter: if (arco not in trocados and arco not in p.fim and p.ponto.x < arco.circ.center.x + arco.circ.r - eps): trocados.append(arco) L.deleta(arco) # Insere denovo com o novo ponto de referencia for arco in trocados: arco.ref = p.ponto insere_na_linha(L, arco, pontos, p.ponto.x, trocados) # apaga a linha desenhos.plot_delete(id_linha) desenhos.plot_delete(id_evento) p.ponto.unplot() return resp
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 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 apaga(self): desenhos.plot_delete(self.aresta_cima) desenhos.plot_delete(self.aresta_baixo) desenhos.plot_delete(self.aresta_esq) desenhos.plot_delete(self.aresta_dir)
def unplot(self): if self.plot_id is not None: desenhos.plot_delete(self.plot_id)
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')
def remove_lineto(self, p): "Apaga a linha ate o ponto p" if p in self.lineto_id.keys() and self.lineto_id[p] is not None: desenhos.plot_delete(self.lineto_id[p])
def hide(self): if self.draw_id != None: plot_delete(self.draw_id) self.draw_id = self.twin.draw_id = None
def hide(self): "apaga o segmento de reta da tela" if self.plot_id != None: desenhos.plot_delete(self.plot_id)
def unhilight(self): desenhos.plot_delete(self.hi_id) self.init.unhilight() self.to.unhilight()
def unhilight_semi_circle(self, up): "Apaga o semi_circulo" if up: return desenhos.plot_delete(self.id_up) return desenhos.plot_delete(self.id_down)
def unhilight(self): "Apaga o 'destaque' do disco" if self.hi is not None: desenhos.plot_delete(self.hi)