def Lee_Preparata (p): P = p[0] diags = [] d = Dcel () d.initPolygon (P) # Atualiza a DCEL colocando as diagonais parar a partição em monótonos monotonos (d, P, diags) n_face_externa = len(P.vertices()) divisoras = len(diags) # Para cada face, constrói um polígono e triangula ele if len (d.f) == 2: return Monotono([P]) for e in d.f: vertices = [e.init] while e.to != vertices[0]: vertices.append (e.to) e = e.prox if len(vertices) != n_face_externa: new_p = Polygon (vertices) new_p.plot("orange") control.sleep() # Triangula o new_p e adiciona as novas diagonais no diags diags.extend (Monotono ([new_p])) new_p.hide() # despinta as arestas for i in range(divisoras): diags[i].hide() diags[i].plot("green")
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 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 Chan (l): n = len (l) if n == 0: return None if n == 1 or n == 2: ret = Polygon (l) ret.plot () ret.extra_info = 'vertices: %d'%n return ret i = 2 while 1: H = min (1<< (1<<i), n) m = H ch = Hull2D (l, m, H) #print ch if ch != None: ch.extra_info = 'vertices: %d'%len (ch.to_list ()) return ch i = i + 1
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 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 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 Bhatta_Sen(l): """Algoritmo otimo proposto por Bhattacharya e Sen para encontrar o fecho convexo de l""" south = north = east = west = 0 # encontrando o ponto mais baixo for i in range(1, len(l)): if l[i].y < l[south].y: south = i elif l[i].y == l[south].y: if l[i].x > l[south].x: south = i if l[i].y > l[north].y: north = i elif l[i].y == l[north].y: if l[i].x > l[north].x: north = i if l[i].x < l[west].x: west = i elif l[i].x == l[west].x: if l[i].y > l[west].y: west = i if l[i].x > l[east].x: east = i elif l[i].x == l[east].x: if l[i].y > l[east].y: east = i fecho = [] dirs = [south, east, north, west] for i in range(0, len(dirs)): j = (i + 1) % 4 if dirs[i] == dirs[j]: continue fecho.append(l[dirs[i]]) S1 = [] a = l[dirs[i]] b = l[dirs[j]] for p in l: if right(a, b, p): S1.append(p) id = a.lineto(b, config.COLOR_ALT4) aux = [] if len(S1) > 0: if dirs[i] == south or dirs[i] == west: aux = bhatta_sen_lower_rec(a, b, S1) else: aux = bhatta_sen_upper_rec(a, b, S1) a.remove_lineto(b, id) if len(aux) > 0: a.lineto(aux[0]) aux[-1].lineto(b) else: a.lineto(b) fecho.extend(aux) if len(l) == 1: fecho = [l[0]] pol = Polygon(fecho) pol.plot() pol.extra_info = "vertices: %d" % len(fecho) return pol
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 Hull2D (P, m, H): #print m, H lines = [] n = len (P) CHs = [] num = n/m a = 0 while a < n: b = min (a+m, n) l = P[a:b] ids = [] for p in l: ids.append (p.hilight ()) ch = Graham (l) #ch.hide () for p in P[a:b]: p.unhilight (ids.pop ()) CHs.append (ch) a = b i0 = 0 # encontrando o ponto mais a direita p0 = CHs[0].pts for ch in CHs: for p in ch.to_list (): if p.x > p0.x: p0 = p elif p.x == p0.x: if p.x > p0.x: p0 = p fecho = [ p0 ] for ch in CHs: ch.hide () #control.sleep (2) for k in range (0, H): Q = [] for ch in CHs: ch.plot () p = ch.pts initial = 1 while 1: direction = area2 (fecho[-1], p, p.next) if direction < 0: p = p.next initial = 0 elif direction == 0 \ and dist2 (fecho[-1], p) \ < dist2 (fecho[-1], p.next): p = p.next initial = 0 elif initial: p = p.next else: Q.append (p) p.hilight () control.sleep () ch.pts = p.prev ch.hide () break control.sleep () p = Q[0] for q in Q[1:]: direction = area2 (fecho[-1], p, q) if direction < 0: p = q elif direction == 0: if (dist2 (fecho[-1], p) < dist2 (fecho[-1], q)): p = q for q in Q: q.unhilight () lines.append (fecho[-1].lineto (p, 'green')) fecho.append (p) if p == p0: #for ch in CHs: ch.hide () #print 'fecho =',`fecho` fecho.pop () for i in lines: control.plot_delete (i) poly = Polygon (fecho) poly.plot () return poly #for ch in CHs: ch.hide () for i in lines: control.plot_delete (i) return None
def Bhatta_Sen (l): """Algoritmo otimo proposto por Bhattacharya e Sen para encontrar o fecho convexo de l""" south = north = east = west = 0 # encontrando o ponto mais baixo for i in range (1, len(l)): if l[i].y < l[south].y: south = i elif l[i].y == l[south].y: if l[i].x > l[south].x: south = i if l[i].y > l[north].y: north = i elif l[i].y == l[north].y: if l[i].x > l[north].x: north = i if l[i].x < l[west].x: west = i elif l[i].x == l[west].x: if l[i].y > l[west].y: west = i if l[i].x > l[east].x: east = i elif l[i].x == l[east].x: if l[i].y > l[east].y: east = i fecho = [] dirs = [ south, east, north, west ] for i in range (0, len (dirs)): j = (i+1) % 4 if dirs[i] == dirs[j]: continue fecho.append (l[dirs[i]]) S1 = [] a = l[dirs[i]] b = l[dirs[j]] for p in l: if right (a, b, p): S1.append (p) id = a.lineto (b, config.COLOR_ALT4) aux = [] if len (S1) > 0: if dirs[i] == south or dirs[i] == west: aux = bhatta_sen_lower_rec (a, b, S1) else: aux = bhatta_sen_upper_rec (a, b, S1) a.remove_lineto (b, id) if len (aux) > 0: a.lineto (aux[0]) aux[-1].lineto (b) else: a.lineto (b) fecho.extend (aux) if len (l) == 1: fecho = [ l[0] ] pol = Polygon (fecho) pol.plot () pol.extra_info = "vertices: %d" %len (fecho) return pol
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