def Brute (l): "Algoritmo forca bruta para encontrar o par de pontos mais distante" if len (l) < 2: return None farthest = 0 a = b = None id = None for i in range (len(l)): for j in range (i + 1, len (l)): dist = dist2 (l[i], l[j]) if dist > farthest: control.freeze_update () if a != None: a.unhilight (hia) if b != None: b.unhilight (hib) if id != None: control.plot_delete (id) farthest = dist a = l[i] b = l[j] hia = a.hilight () hib = b.hilight () id = a.lineto (b) control.thaw_update () control.update () ret = Segment (a, b) ret.extra_info = 'distancia: %.2f'%math.sqrt (dist2 (a, b)) return ret
def recursive_ham_sandwich(G1, G2, p1, p2, T): if len(G1) < len(G2): return recursive_ham_sandwich(G2, G1, p2, p1, T) T, is_base = new_interval(G1, G2, p1, p2, T) if is_base: valid_answers = [] for g in G1: for h in G2: p = g.intersect(h) if p and isinstance(p.dual(), Line): valid_answers.append(p.dual()) return valid_answers, G1 + G2 t = new_trapezoid(G1, p1, T) t_ids = [] control.freeze_update() for i in range(4): j = (i + 1) % 4 t_ids.append( control.plot_segment(t[i].x, t[i].y, t[j].x, t[j].y, 'yellow')) control.sleep() control.thaw_update() G1, p1 = discard_lines(G1, p1, t) G2, p2 = discard_lines(G2, p2, t) for id in t_ids: control.plot_delete(id) return recursive_ham_sandwich(G1, G2, p1, p2, T)
def Brute (l): "Algoritmo forca bruta para encontrar o par de pontos mais proximo" if len (l) < 2: return None closest = float("inf") a = b = None id = None for i in range (len(l)): for j in range (i + 1, len (l)): dist = dist2 (l[i], l[j]) if dist < closest: control.freeze_update () if a != None: a.unhilight (hia) if b != None: b.unhilight (hib) if id != None: control.plot_delete (id) closest = dist a = l[i] b = l[j] hia = a.hilight () hib = b.hilight () id = a.lineto (b) control.thaw_update() control.update () a.hilight('green') b.hilight('green') ret = Segment (a, b) ret.extra_info = 'distancia: %.2f'%math.sqrt (dist2 (a, b)) print(math.sqrt (dist2 (a, b))) return ret
def destaca_segs(lista_segs, string_cor): # pinta segmentos com cores do passado, presente, vizinho ou intersectado global cores control.freeze_update () for seg in lista_segs: if seg != None: seg.hilight2(cores[string_cor]) control.thaw_update ()
def draw_interval(should_plot=True): control.thaw_update() for i in range(2): if not ids[i] == None: control.plot_delete(ids[i]) if T[i] != -inf and T[i] != +inf and should_plot: ids[i] = control.plot_vert_line(T[i], 'yellow') control.sleep() control.freeze_update()
def plot(self): if self.rank != 0: return self.drawing = [] for i in range(3): self.drawing.append(self.P[i - 1].inner.lineto( self.P[i].inner, COLOR_TRIANG)) control.thaw_update() control.update() control.freeze_update()
def mergehull_rec (l): """Funcao recursiva que implementa o Merge Hull Retorna os pontos com coordenada x minima e maxima do fecho convexo encontrado, alem do proprio fecho. """ n = len (l) if n == 1: #l[0].prev = l[0].next = l[0] pol = Polygon ( [ l[0] ] ) pol.plot () #control.sleep () return (l[0], l[0], pol) # Divisao l1 = l[:n/2] l2 = l[n/2:] id = control.plot_vert_line ((l2[0].x + l1[-1].x) / 2.) control.sleep () # Conquista ch1 = mergehull_rec (l1) ch2 = mergehull_rec (l2) v = ch1[1] u = ch2[0] control.plot_delete (id) # Combinar sup = superior_tangent (v, u) id_sup = sup[0].lineto (sup[1], config.COLOR_ALT1) inf = inferior_tangent (v, u) id_inf = inf[0].lineto (inf[1], config.COLOR_ALT1) control.freeze_update () control.plot_delete (id_sup) control.plot_delete (id_inf) ch1[2].hide () ch2[2].hide () sup[0].prev = sup[1] sup[1].next = sup[0] inf[0].next = inf[1] inf[1].prev = inf[0] ch1[2].pts = inf[0] ch1[2].plot () control.thaw_update () return (ch1[0], ch2[1], ch1[2])
def e_lineto(p, q, color=config.COLOR_PRIM): if max(p.inf, q.inf) > 0: return keep = p.inner.lineto(q.inner, color) control.thaw_update() control.update() control.freeze_update() control.sleep() p.inner.remove_lineto(q, keep)
def mergehull_rec(l): """Funcao recursiva que implementa o Merge Hull Retorna os pontos com coordenada x minima e maxima do fecho convexo encontrado, alem do proprio fecho. """ n = len(l) if n == 1: #l[0].prev = l[0].next = l[0] pol = Polygon([l[0]]) pol.plot() #control.sleep () return (l[0], l[0], pol) # Divisao l1 = l[:n // 2] l2 = l[n // 2:] id = control.plot_vert_line((l2[0].x + l1[-1].x) / 2.) control.sleep() # Conquista ch1 = mergehull_rec(l1) ch2 = mergehull_rec(l2) v = ch1[1] u = ch2[0] control.plot_delete(id) # Combinar sup = superior_tangent(v, u) id_sup = sup[0].lineto(sup[1], config.COLOR_ALT1) inf = inferior_tangent(v, u) id_inf = inf[0].lineto(inf[1], config.COLOR_ALT1) control.freeze_update() control.plot_delete(id_sup) control.plot_delete(id_inf) ch1[2].hide() ch2[2].hide() sup[0].prev = sup[1] sup[1].next = sup[0] inf[0].next = inf[1] inf[1].prev = inf[0] ch1[2].pts = inf[0] ch1[2].plot() control.thaw_update() return (ch1[0], ch2[1], ch1[2])
def Fortune(P): Q = event_queue(P) V = DCEL() T = BST() for event in Q.keys(): V.add_face(event.face) while Q: q = Q.pop() q.point.hilight() par_plots, sweep = plot_all(T.all_leaves(), V, q.point.y) control.sleep() if q.is_site_event: handle_site_event(q, T, Q, V) else: handle_circle_event(q, T, Q, V) q.point.unplot() control.sleep() if len(Q) > 0: next_y = Q.top().point.y line_y = q.point.y leaves = T.all_leaves() # while not math.isclose(line_y, next_y, rel_tol=4*FORTUNE_PLOT_RATE): # FORTUNE_PLOT_RATE = abs(line_y - next_y)/100 while line_y > next_y: control.thaw_sleep() if abs(line_y - next_y) > FORTUNE_PLOT_RATE * 10**3: line_y -= abs(line_y - next_y) / 10 else: line_y -= FORTUNE_PLOT_RATE unplot_all(par_plots, V.hedges, sweep) par_plots, sweep = plot_all(leaves, V, line_y) control.thaw_update() control.update() control.freeze_update() unplot_all(par_plots, V.hedges, sweep) q.point.unhilight() control.update() vertices = [v.p for v in V.vertices] borders = find_borders(P + vertices) finalize_voronoi(V, T, borders) for h in V.hedges: h.segment.plot() return V
def points_to_lines(P, color): G = [] for p in P: control.thaw_update() p.tk.hilight(color) control.sleep() control.freeze_update() g = p.dual() g.plot_id = control.plot_line(0, g(0), 1, g(1), color) G.append(g) p.tk.unhilight() p.tk.unplot() control.sleep() return G
def update_points(p1, p2): global a, b, id, hia, hib if (a != None and b != None): if (prim.dist2(p1, p2) >= prim.dist2(a, b)): return control.freeze_update() if a != None: a.unhilight(hia) if b != None: b.unhilight(hib) if id != None: control.plot_delete(id) a = p1 b = p2 hia = a.hilight() hib = b.hilight() id = a.lineto(b) control.thaw_update() control.update()
def partition(P, p, r, point_p, point_r): '''Recebe uma coleção de pontos em posição geral, com pelo menos 3 pontos tal que os pontos de índice p e r são extremos consecutivos na fronteira do fecho convexo da coleção no sentido anti-horário. Rearranja a coleção de pontos e devolve (s,q) para o algoritmo do QuickHull.''' q = extreme(P, p, r) points[(point_r, P[q])] = point_r.lineto(P[q], 'cyan') points[(P[q], point_p)] = P[q].lineto(point_p, 'cyan') control.thaw_update() control.update() control.freeze_update() control.sleep() P[p + 1], P[q] = P[q], P[p + 1] s = q = r for point, id in ids: point.unhilight(id) for k in range(r - 1, p + 1, -1): if left(P[p], P[p + 1], P[k]): id = P[k].hilight('green') ids.append((P[k], id)) s -= 1 P[s], P[k] = P[k], P[s] elif left(P[p + 1], P[r], P[k]): id = P[k].hilight('red') ids.append((P[k], id)) s -= 1 q -= 1 P[k], P[q] = P[q], P[k] if s != q: P[k], P[s] = P[s], P[k] control.thaw_update() control.update() control.freeze_update() control.sleep() s -= 1 q -= 1 P[q], P[p + 1] = P[p + 1], P[q] if s != q: P[s], P[p + 1] = P[p + 1], P[s] s -= 1 P[s], P[p] = P[p], P[s] return s, q
def triang (a, b, c): "desenha (e apaga) os lados do triangulo abc" a.lineto (c, config.COLOR_PRIM) #b.lineto (a, config.COLOR_PRIM) c.lineto (b, config.COLOR_PRIM) c.hilight () control.thaw_update () control.update () control.freeze_update () control.sleep () c.unhilight () a.remove_lineto (c) #b.remove_lineto (a) c.remove_lineto (b)
def triang(a, b, c): "desenha (e apaga) os lados do triangulo abc" a.lineto(c, config.COLOR_PRIM) #b.lineto (a, config.COLOR_PRIM) c.lineto(b, config.COLOR_PRIM) c.hilight() control.thaw_update() control.update() control.freeze_update() control.sleep() c.unhilight() a.remove_lineto(c) #b.remove_lineto (a) c.remove_lineto(b)
def ham_sandwich(P1, P2): G1 = points_to_lines(P1, 'red') G2 = points_to_lines(P2, 'blue') valid_answers, missing_lines = recursive_ham_sandwich( G1, G2, len(G1) // 2, len(G2) // 2, (-inf, inf)) for l in valid_answers: if verify_solution(P1, P2, l): control.freeze_update() p = l.dual() p.tk = pt(p.x, p.y) p.tk.plot('green') control.sleep() control.thaw_update() delete_stuff(missing_lines + [p]) return l return None
def ear_tip(P, v): '''Recebe um polígono P e um vértice v desse polígono, e decide se ele é uma ponta de orelha''' u = P.prev(v) w = P.next(v) v.hilight('green') u.hilight('yellow') w.hilight('yellow') control.sleep() control.thaw_update() control.update() diag = diagonal(P, u, w) u.unhilight() w.unhilight() if not diag: v.unhilight() control.sleep() control.thaw_update() control.update() return diag
def discard_lines(G, p, t): nG = [] b = 0 for l in G: control.freeze_update() new_plot_id = control.plot_line(0, l(0), 1, l(1), 'cyan') control.sleep() control.thaw_update() control.freeze_update() is_under, is_above = intersects_trapezoid(l, t) if not (is_under or is_above): nG.append(l) elif is_under: b += 1 if (is_under or is_above): delete_stuff([l]) control.plot_delete(new_plot_id) control.sleep() control.thaw_update() return nG, p - b
def Brute_Force(segmentos): cores = (config.COLOR_ALT1, config.COLOR_ALT7, config.COLOR_ALT6) for segmento in segmentos: segmento.intersected = False for i in range (len(segmentos)): control.freeze_update () hii = segmentos[i].hilight2 (cores[1]) control.thaw_update () control.sleep() for j in range (i + 1, len (segmentos)): control.freeze_update () hij = segmentos[j].hilight2(cores[0]) control.thaw_update () control.sleep() if prim.inter(segmentos[i],segmentos[j]): control.freeze_update () segmentos[i].hilight2 (cores[2]) segmentos[j].hilight2 (cores[2]) segmentos[i].intersected = True segmentos[j].intersected = True control.thaw_update () segmentos[j].unhilight (hij) segmentos[i].unhilight (hii)
def Quickhull(P): '''Recebe uma coleção de pontos P e devolve seu fecho convexo''' n = len(P) if n == 1: return [P[0]] # encontra primeiro ponto extremo k = 0 for i in range(n): # desempata por x if P[i].y < P[k].y or (P[i].y == P[k].y and P[i].x < P[k].x): k = i P[0], P[k] = P[k], P[0] # encontra extremo consecutivo ao primeiro i = 1 dist = 0 for j in range(2, n): if right(P[0], P[i], P[j]): i = j # desempata pelo mais distante elif collinear(P[0], P[i], P[j]) and dist2(P[0], P[i]) < dist2(P[0], P[j]): i = j P[n - 1], P[i] = P[i], P[n - 1] P[0].lineto(P[n - 1], 'cyan') control.thaw_update() control.update() control.freeze_update() control.sleep() quick = quickhull_rec(P, 0, n - 1, Point(P[0].x, P[0].y), Point(P[n - 1].x, P[n - 1].y)) for p in quick: p.hilight('yellow') return quick
def triangulation(n, P): '''Recebe um polígono P com n lados e devolve a triangulação de P''' ears = find_ears(P) v3 = P.pts while n > 3: v2 = v3 while not ears[v2]: v2 = P.next(v2) v2.hilight("blue") v1 = P.prev(v2) v3 = P.next(v2) v1.lineto(v3, "blue") control.sleep() control.thaw_update() control.update() print(v1, v3) v2.unhilight() control.sleep() control.thaw_update() control.update() P.remove_vertex(v2) n -= 1 ears[v1] = ear_tip(P, v1) ears[v3] = ear_tip(P, v3)
def IncrProb(l): "Algoritmo incremental probabilistico para encontrar o fecho convexo" if len(l) == 0: return None # Embaralhando o vetor de entrada for i in range(len(l) - 1, -1, -1): index = int(random.uniform(0, i + 1)) aux = l[i] l[i] = l[index] l[index] = aux # Inicializando alguns campos... for i in range(0, len(l)): l[i].L = [] l[i].interior = 0 # Criando um fecho convexo com 1 ponto fecho = Polygon([l[0]]) fecho.plot() length = 1 k = 0 hi = l[k].hilight() # Como nao posso admitir que os pontos estao em posicao geral, # preciso tomar cuidado ate' conseguir um fecho convexo com # 3 pontos for k in range(1, len(l)): pts = fecho.pts l[k - 1].unhilight(hi) hi = l[k].hilight() control.thaw_update() if length == 1: if l[k].x == pts.x and l[k].y == pts.y: continue fecho.hide() pts.next = pts.prev = l[k] l[k].next = l[k].prev = pts fecho.pts = pts fecho.plot() length = length + 1 elif length == 2: next = pts.next dir = area2(pts, next, l[k]) if dir == 0: #Mais um ponto colinear -> pega o par mais distante fecho.hide() dist_pts_next = dist2(pts, next) dist_pts_lk = dist2(pts, l[k]) dist_next_lk = dist2(next, l[k]) if dist_pts_next >= dist_pts_lk and dist_pts_next >= dist_next_lk: a = pts b = next elif dist_pts_lk >= dist_pts_next and dist_pts_lk >= dist_next_lk: a = pts b = l[k] elif dist_next_lk >= dist_pts_lk and dist_next_lk >= dist_pts_next: a = next b = l[k] else: print('pau!!!') a.next = a.prev = b b.next = b.prev = a fecho.pts = a fecho.plot() continue fecho.hide() # Um ponto /nao/ colinear :) -> tomar cuidado com a # orientacao if dir > 0: pts.prev = next.next = l[k] l[k].next = pts l[k].prev = next else: pts.next = next.prev = l[k] l[k].prev = pts l[k].next = next length = length + 1 fecho.pts = pts fecho.plot() O = classify(fecho, l, k) break # Ja temos um fecho com 3 pontos -> basta cresce-lo for k in range(k + 1, len(l)): pts = fecho.pts l[k - 1].unhilight(hi) hi = l[k].hilight() control.thaw_update() if l[k].interior: control.sleep() continue l[k].remove_lineto(l[k].intersect) control.sleep() tan = vertices_tangentes(l[k].intersect, l[k]) l[k].intersect.L.remove(l[k]) l0 = [] l1 = [] # atualizando a classificacao dos pontos vertex = tan[0] while vertex != tan[1]: for p in vertex.L: id = p.hilight(config.COLOR_ALT3) p.remove_lineto(p.intersect) if p == l[k]: p.unhilight(id) continue if left(l[k], O, p): if left_on(tan[0], l[k], p): p.interior = 1 p.intersect = None else: p.intersect = tan[0] p.lineto(p.intersect, config.COLOR_ALT1) l0.append(p) else: if left_on(l[k], tan[1], p): p.interior = 1 p.intersect = None else: p.intersect = l[k] p.lineto(p.intersect, config.COLOR_ALT1) l1.append(p) p.unhilight(id) vertex = vertex.next tan[0].L = l0 l[k].L = l1 # atualizando o fecho control.freeze_update() fecho.hide() tan[0].next.prev = None tan[0].next = l[k] l[k].prev = tan[0] if tan[1].prev: tan[1].prev.next = None tan[1].prev = l[k] l[k].next = tan[1] fecho.pts = tan[0] fecho.plot() control.thaw_update() l[k].unhilight(hi) fecho.plot() fecho.extra_info = 'vertices: %d' % len(fecho.to_list()) return fecho
def Incremental (l): "Algoritmo incremental para o problema do fecho convexo de uma lista de pontos" if len (l) == 0: return None # crio um fecho c/ um ponto fecho = Polygon ([ l[0] ]) fecho.plot () # Como nao posso admitir que os pontos estao em posicao geral, # preciso tomar cuidado ate encontrar tres pontos nao colineares # :-( length = 1 k = 0 hi = l[k].hilight () for k in range (1, len (l)): pts = fecho.pts l[k-1].unhilight (hi) hi = l[k].hilight () control.thaw_update () if length == 1: if l[k].x == pts.x and l[k].y == pts.y: continue fecho.hide () pts.next = pts.prev = l[k] l[k].next = l[k].prev = pts fecho.pts = pts fecho.plot () length = length + 1 elif length == 2: next = pts.next dir = area2 (pts, next, l[k]) if dir == 0: #Mais um ponto colinear -> pega o par mais distante fecho.hide () dist_pts_next = dist2 (pts, next) dist_pts_lk = dist2 (pts, l[k]) dist_next_lk = dist2 (next, l[k]) if dist_pts_next >= dist_pts_lk and dist_pts_next >= dist_next_lk: a = pts b = next elif dist_pts_lk >= dist_pts_next and dist_pts_lk >= dist_next_lk: a = pts b = l[k] elif dist_next_lk >= dist_pts_lk and dist_next_lk >= dist_pts_next: a = next b = l[k] else: print 'pau!!!' a.next = a.prev = b b.next = b.prev = a fecho.pts = a fecho.plot () continue fecho.hide () # Ponto nao colinear :) - basta tomar cuidado p/ # construir o poligono c/ a direcao certa if dir > 0: pts.prev = next.next = l[k] l[k].next = pts l[k].prev = next else: pts.next = next.prev = l[k] l[k].prev = pts l[k].next = next length = length + 1 fecho.pts = pts fecho.plot () break # Ja tenho um fecho com 3 pontos -> basta "cresce-lo" for k in range (k+1, len (l)): pts = fecho.pts l[k-1].unhilight (hi) hi = l[k].hilight () control.thaw_update () tan = vertices_tangentes (fecho, l[k]) # l[k] esta fora do fecho atual <=> len (tan) == 2 if len (tan) == 2: control.freeze_update () fecho.hide () tan[0].next.prev = None tan[0].next = l[k] l[k].prev = tan[0] if tan[1].prev: tan[1].prev.next = None tan[1].prev = l[k] l[k].next = tan[1] fecho.pts = tan[0] fecho.plot () control.thaw_update () l[k].unhilight (hi) fecho.plot () fecho.extra_info = 'vertices: %d'%len (fecho.to_list ()) return fecho
def __update(self): control.thaw_update() control.update() control.freeze_update() control.sleep()
def Graham(l): "Algoritmo de Graham para achar o fecho convexo de uma lista l de pontos" if len(l) == 0: return None # So um ponto foi passado. Retorna um fecho c/ apenas um ponto if len(l) == 1: ret = Polygon(l) ret.plot() ret.extra_info = 'vertices: 1' return ret p0 = l[0] # acha o ponto mais baixo for i in range(1, len(l)): if l[i].y < p0.y: p0 = l[i] elif l[i].y == p0.y: if l[i].x > p0.x: p0 = l[i] l.remove(p0) def cmp(x, y, z=p0): """Funcao para ordenar os pontos ao redor de z Usada com a funcao sort, ordena os pontos de uma lista de acordo com o angulo que cada ponto forma com o ponto z e a reta horizontal. Em caso de empate, o ponto mais distante aparece primeiro.""" area = area2(z, x, y) if area > 0: return -1 elif area < 0: return 1 else: dist_z_x = dist2(z, x) dist_z_y = dist2(z, y) if dist_z_y < dist_z_x: return -1 return dist_z_y > dist_z_x # Ordena os pontos pelo seus angulos l.sort(cmp) # eliminando pontos colineares l2 = [l[0]] for i in range(1, len(l)): if collinear(p0, l[i - 1], l[i]): continue l2.append(l[i]) l = l2 # So sobraram dois pontos -> retorna fecho c/ os dois if len(l) < 2: ret = Polygon([p0, l[0]]) ret.plot() ret.extra_info = 'vertices: 2' return ret pilha = [p0, l[0], l[1]] p0.lineto(l[0]) l[0].lineto(l[1]) control.sleep() for i in range(2, len(l)): l[i].hilight() pilha[-1].lineto(l[i]) control.sleep() while not left(pilha[-2], pilha[-1], l[i]): pilha[-2].remove_lineto(pilha[-1]) pilha[-1].remove_lineto(l[i]) pilha.pop() pilha[-1].lineto(l[i]) control.sleep() pilha.append(l[i]) l[i].unhilight() pilha[-1].lineto(pilha[0]) for i in range(0, len(pilha) - 1): pilha[i].remove_lineto(pilha[i + 1]) pilha[-1].remove_lineto(pilha[0]) poligono = Polygon(pilha) poligono.plot() control.thaw_update() poligono.extra_info = 'vertices: %d' % len(poligono.to_list()) return poligono
def fortune(l, triang): # Inicializa as estruturas de dados Q = EventQueue() Beach = BeachLine() Vor = dcel() CircDraw = draw_circ_events() # # Remove pontos repetidos na entrada l = unique_points(l) # Inicializa as variáveis global DelaunayTriangDraw DelaunayTriangDraw = triang lineid = None partiallines = None parabola_list = None max_x = min_x = l[0].x max_y = min_y = l[0].y first_y = None high_y = None cur_c = None y_count = 1 last_y = None # # Busca a bounding box dos pontos, e insere os pontos na fila for p in l: if p.x > max_x: max_x = p.x if p.x < min_x: min_x = p.x if p.y > max_y: max_y = p.y if p.y < min_y: min_y = p.y if high_y is None: high_y = p.y elif p.y > high_y: high_y = p.y y_count = 1 elif p.y == high_y: y_count = y_count + 1 Q.put(Ponto(p.x, p.y), Ponto(p.x, p.y)) # Desenhas os pontos um pouco maiores control.plot_disc(p.x, p.y, config.COLOR_POINT, 4) # # Define os bounds da tela yd = max_y - min_y xd = max_x - min_x dd = max(yd, xd) mfactor = 0.7 bounds = { "maxx": (max_x + min_x) / 2 + dd * mfactor, "minx": (max_x + min_x) / 2 - dd * mfactor, "maxy": (max_y + min_y) / 2 + dd * mfactor, "miny": (max_y + min_y) / 2 - dd * mfactor } Beach.bounds = bounds # Caso os primeiros pontos tenham a mesma y-coordenada, trata este caso particular if y_count > 1: aligned = [] for i in range(y_count): aligned.append(Q.takeHighest()) aligned = list(reversed(aligned)) for i in range(len(aligned) - 1): drawDelaunayEdge(aligned[i].x, aligned[i].y, aligned[i + 1].x, aligned[i + 1].y) Beach.create_particular(aligned) # Loop principal while Q.n > 0: atual = Q.takeHighest() ## Remove o desenho do ponto evento círculo da iteração anterior, e desenha a nova posição da linha de varredura control.freeze_update() if cur_c is not None: control.plot_delete(cur_c) cur_c = None lineid = control.plot_horiz_line(atual.y) ## # Trata evento ponto ou círculo if atual.isPonto: trataPonto(atual, Q, Beach, CircDraw) else: cur_c = control.plot_disc(atual.x, atual.y, config.COLOR_ALT5, 4) CircDraw.rem_point(atual.x, atual.y) trataCirculo(atual, Q, Beach, CircDraw) # # Desenha as parábolas e as arestas de Voronoi parciais parabola_list = Beach.draw_parabolas(atual.y) partiallines = Beach.draw_partial(atual.y) control.thaw_update() control.update() control.sleep() # Remove o desenho das parábolas e da linha de varredura desta iteração if lineid is not None: control.plot_delete(lineid) if parabola_list is not None: for i in parabola_list: control.plot_delete(i) # Remove as parábolas que 'sairam da tela', remove seus respectivos eventos e o desenho destes eventos evlist = Beach.trata_extremos(atual.y) for ev in evlist: CircDraw.rem_point(ev.x, ev.y) Q.take(ev) last_y = atual.y # Atualiza o desenho para a última iteração lower = last_y - 2 * (Beach.bounds["maxy"] - Beach.bounds["miny"]) partiallines = Beach.draw_partial(lower) if cur_c is not None: control.plot_delete(cur_c) cur_c = None # Desenha as arestas de Delaunay que não foram consideradas durante o algoritmo (por conta das parabolas serem removidas) if Beach.llist: for i in range(len(Beach.llist) - 1): p1, q1 = Beach.llist[i] p2, q2 = Beach.llist[i + 1] x, y = lineIntersect(p1, q1, p2, q2) if x is not None and x < Beach.bounds["minx"]: Beach.llist[i + 1] = [p1, q1] if q1 == p2: drawDelaunayEdge(p1.x, p1.y, q2.x, q2.y) elif q1 == p1: drawDelaunayEdge(p2.x, p2.y, q2.x, q2.y) elif q2 == p2: drawDelaunayEdge(p1.x, p1.y, q1.x, q1.y) else: drawDelaunayEdge(p2.x, p2.y, q1.x, q1.y) if Beach.rlist: for i in range(len(Beach.rlist) - 1): p1, q1 = Beach.rlist[i] p2, q2 = Beach.rlist[i + 1] x, y = lineIntersect(p1, q1, p2, q2) if x is not None and x > Beach.bounds["maxx"]: Beach.rlist[i + 1] = [p1, q1] if q1 == p2: drawDelaunayEdge(p1.x, p1.y, q2.x, q2.y) elif q1 == p1: drawDelaunayEdge(p2.x, p2.y, q2.x, q2.y) elif q2 == p2: drawDelaunayEdge(p1.x, p1.y, q1.x, q1.y) else: drawDelaunayEdge(p2.x, p2.y, q1.x, q1.y) # Constroi a DCEL Vor.constroi(edges) return Vor
def Graham (l): "Algoritmo de Graham para achar o fecho convexo de uma lista l de pontos" if len (l) == 0: return None # So um ponto foi passado. Retorna um fecho c/ apenas um ponto if len (l) == 1: ret = Polygon (l) ret.plot () ret.extra_info = 'vertices: 1' return ret p0 = l[0] # acha o ponto mais baixo for i in range (1, len(l)): if l[i].y < p0.y: p0 = l[i] elif l[i].y == p0.y: if l[i].x > p0.x: p0 = l[i] l.remove (p0) def cmp (x, y, z = p0): """Funcao para ordenar os pontos ao redor de z Usada com a funcao sort, ordena os pontos de uma lista de acordo com o angulo que cada ponto forma com o ponto z e a reta horizontal. Em caso de empate, o ponto mais distante aparece primeiro.""" area = area2 (z, x, y) if area > 0: return -1 elif area < 0: return 1 else: dist_z_x = dist2 (z, x) dist_z_y = dist2 (z, y) if dist_z_y < dist_z_x: return -1 return dist_z_y > dist_z_x # Ordena os pontos pelo seus angulos l.sort (cmp) # eliminando pontos colineares l2 = [ l[0] ] for i in range (1, len (l)): if collinear (p0, l[i-1], l[i]): continue l2.append (l[i]) l = l2 # So sobraram dois pontos -> retorna fecho c/ os dois if len (l) < 2: ret = Polygon ( [ p0, l[0] ] ) ret.plot () ret.extra_info = 'vertices: 2' return ret pilha = [ p0, l[0], l[1] ] p0.lineto (l[0]) l[0].lineto (l[1]) control.sleep () for i in range (2, len(l)): l[i].hilight () pilha[-1].lineto (l[i]) control.sleep () while not left (pilha[-2], pilha[-1], l[i]): pilha[-2].remove_lineto (pilha[-1]) pilha[-1].remove_lineto (l[i]) pilha.pop () pilha[-1].lineto (l[i]) control.sleep () pilha.append (l[i]) l[i].unhilight () pilha[-1].lineto (pilha[0]) for i in range (0, len(pilha)-1): pilha[i].remove_lineto (pilha[i+1]) pilha[-1].remove_lineto (pilha[0]) poligono = Polygon (pilha) poligono.plot () control.thaw_update () poligono.extra_info = 'vertices: %d'%len (poligono.to_list ()) return poligono
def IncrProb (l): "Algoritmo incremental probabilistico para encontrar o fecho convexo" if len (l) == 0: return None # Embaralhando o vetor de entrada for i in range (len (l) -1, -1, -1): index = int (random.uniform (0, i+1)) aux = l[i] l[i] = l[index] l[index] = aux # Inicializando alguns campos... for i in range (0, len(l)): l[i].L = [] l[i].interior = 0 # Criando um fecho convexo com 1 ponto fecho = Polygon ([ l[0] ]) fecho.plot () length = 1 k = 0 hi = l[k].hilight () # Como nao posso admitir que os pontos estao em posicao geral, # preciso tomar cuidado ate' conseguir um fecho convexo com # 3 pontos for k in range (1, len (l)): pts = fecho.pts l[k-1].unhilight (hi) hi = l[k].hilight () control.thaw_update () if length == 1: if l[k].x == pts.x and l[k].y == pts.y: continue fecho.hide () pts.next = pts.prev = l[k] l[k].next = l[k].prev = pts fecho.pts = pts fecho.plot () length = length + 1 elif length == 2: next = pts.next dir = area2 (pts, next, l[k]) if dir == 0: #Mais um ponto colinear -> pega o par mais distante fecho.hide () dist_pts_next = dist2 (pts, next) dist_pts_lk = dist2 (pts, l[k]) dist_next_lk = dist2 (next, l[k]) if dist_pts_next >= dist_pts_lk and dist_pts_next >= dist_next_lk: a = pts b = next elif dist_pts_lk >= dist_pts_next and dist_pts_lk >= dist_next_lk: a = pts b = l[k] elif dist_next_lk >= dist_pts_lk and dist_next_lk >= dist_pts_next: a = next b = l[k] else: print('pau!!!') a.next = a.prev = b b.next = b.prev = a fecho.pts = a fecho.plot () continue fecho.hide () # Um ponto /nao/ colinear :) -> tomar cuidado com a # orientacao if dir > 0: pts.prev = next.next = l[k] l[k].next = pts l[k].prev = next else: pts.next = next.prev = l[k] l[k].prev = pts l[k].next = next length = length + 1 fecho.pts = pts fecho.plot () O = classify (fecho, l, k) break # Ja temos um fecho com 3 pontos -> basta cresce-lo for k in range (k+1, len (l)): pts = fecho.pts l[k-1].unhilight (hi) hi = l[k].hilight () control.thaw_update () if l[k].interior: control.sleep () continue l[k].remove_lineto (l[k].intersect) control.sleep () tan = vertices_tangentes (l[k].intersect, l[k]) l[k].intersect.L.remove (l[k]) l0 = [] l1 = [] # atualizando a classificacao dos pontos vertex = tan[0] while vertex != tan[1]: for p in vertex.L: id = p.hilight (config.COLOR_ALT3) p.remove_lineto (p.intersect) if p == l[k]: p.unhilight (id) continue if left (l[k], O, p): if left_on (tan[0], l[k], p): p.interior = 1 p.intersect = None else: p.intersect = tan[0] p.lineto (p.intersect, config.COLOR_ALT1) l0.append (p) else: if left_on (l[k], tan[1], p): p.interior = 1 p.intersect = None else: p.intersect = l[k] p.lineto (p.intersect, config.COLOR_ALT1) l1.append (p) p.unhilight (id) vertex = vertex.next tan[0].L = l0 l[k].L = l1 # atualizando o fecho control.freeze_update () fecho.hide () tan[0].next.prev = None tan[0].next = l[k] l[k].prev = tan[0] if tan[1].prev: tan[1].prev.next = None tan[1].prev = l[k] l[k].next = tan[1] fecho.pts = tan[0] fecho.plot () control.thaw_update () l[k].unhilight (hi) fecho.plot () fecho.extra_info = 'vertices: %d'%len (fecho.to_list ()) return fecho
def Diameter (l): """Algoritmo Diametro para encontrar o par de pontos mais distantes Ele consiste de: - determinar o fecho convexo dos pontos passados - determinar o conjunto de pares antipodas do fecho convexo - determinar o par antipoda cujos pontos estao a uma distancia maxima """ if len (l) < 2: return None if len (l) == 2: ret = Segment (l[0], l[1]) ret.extra_info = 'distancia: %.2f'%math.sqrt (dist2 (l[0], l[1])) return ret ch = Graham (l) ch.hide () ch.plot (config.COLOR_ALT4) control.sleep () pairs = antipodes (ch) cores = (config.COLOR_ALT1,) #print `pairs` i=0 for p,q in pairs: p.hilight (cores[i]) q.hilight (cores[i]) p.lineto (q, cores[i]) i = (i+1) % len (cores) control.sleep () farthest = dist2 (pairs[0][0], pairs[0][1]) a = pairs[0][0] b = pairs[0][1] hia = a.hilight () hib = b.hilight () id = a.lineto (b) for i in range (1, len (pairs)): dist = dist2 (pairs[i][0], pairs[i][1]) if dist > farthest: control.freeze_update () a.unhilight (hia) b.unhilight (hib) control.plot_delete (id) farthest = dist a = pairs[i][0] b = pairs[i][1] hia = a.hilight () hib = b.hilight () id = a.lineto (b) control.thaw_update () ret = Segment (a, b) ret.extra_info = 'distancia: %.2f'%math.sqrt (farthest) return ret
def Diameter(l): """Algoritmo Diametro para encontrar o par de pontos mais distantes Ele consiste de: - determinar o fecho convexo dos pontos passados - determinar o conjunto de pares antipodas do fecho convexo - determinar o par antipoda cujos pontos estao a uma distancia maxima """ if len(l) < 2: return None if len(l) == 2: ret = Segment(l[0], l[1]) ret.extra_info = 'distancia: %.2f' % math.sqrt(dist2(l[0], l[1])) return ret ch = Graham(l) ch.hide() ch.plot(config.COLOR_ALT4) control.sleep() pairs = antipodes(ch) cores = (config.COLOR_ALT1, ) #print `pairs` i = 0 for p, q in pairs: p.hilight(cores[i]) q.hilight(cores[i]) p.lineto(q, cores[i]) i = (i + 1) % len(cores) control.sleep() farthest = dist2(pairs[0][0], pairs[0][1]) a = pairs[0][0] b = pairs[0][1] hia = a.hilight() hib = b.hilight() id = a.lineto(b) for i in range(1, len(pairs)): dist = dist2(pairs[i][0], pairs[i][1]) if dist > farthest: control.freeze_update() a.unhilight(hia) b.unhilight(hib) control.plot_delete(id) farthest = dist a = pairs[i][0] b = pairs[i][1] hia = a.hilight() hib = b.hilight() id = a.lineto(b) control.thaw_update() ret = Segment(a, b) ret.extra_info = 'distancia: %.2f' % math.sqrt(farthest) return ret