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('blue') control.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('blue') control.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() control.sleep()
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('blue') dcel.add_edge (d.init, d.to) diags.append(d) control.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) control.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('blue') dcel.add_edge (d.init, d.to) diags.append(d) control.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) control.sleep()
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 visit(self, u, target): u.setVisited(True) v = self.findNeighbor(u) while v is not None: # Printando o segmento atual do grafo seg = Segment(Point(u.x, u.y), Point(v.x, v.y)) seg.plot('cyan') control.sleep() # Continuar o DFS if (v == target): self.solved = True return 1 self.visit(v, target) # Condicao de parada do DFS if(self.solved): return 1 # Retirando o print do segmento seg.hide() control.sleep() # Pegar o próximo vizinho v = self.findNeighbor(u)
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 visivel(T, S, p, i): a = S[i] a.visivel = False #Até que se prove o contrário if (a is p): a.visivel = True return a.visivel #Testa se a reta p->s[i] passa por dentro do polígono # de p. if (p.prev != p): #p está em algum polígono if (noCone(p.prev, p, p.next, a)): a.visivel = False #Falhou no cone return a.visivel if (i == 0 or not collinear(p, S[i - 1], a)): segMin = T.getMin() if (segMin is None): a.visivel = True #seg min é null return a.visivel #Testando intersec com min a.visivel = not intersectaProp(segMin, Segment(p, a)) elif (not S[i - 1].visivel): # Anterior não é visível a.visivel = False else: if (S[i - 1].prev != S[i - 1]): #S[i-1] esta em um polígono if (noCone(S[i - 1].prev, S[i - 1], S[i - 1].next, a)): a.visivel = False print("Falhou no cone 2") return a.visivel segTemp = Segment(S[i - 1], a) seg2 = T.getProx(S[i - 1]) # Testando o segmento do meio # if (seg2 is None): a.visivel = True else: a.visivel = not intersectaProp(seg2, segTemp) return a.visivel
def newEdge(self, x1, y1, x2, y2): vertex1 = self.findVertex(x1, y1) vertex2 = self.findVertex(x2, y2) if (vertex1 != None) and (vertex2 != None): self.allEdge.append(Edge(vertex1, vertex2)) point1 = Point(vertex1.getX(), vertex1.getY()) point2 = Point(vertex2.getX(), vertex2.getY()) Printo(Segment(point1, point2)) else: print("Falhou em newEdge -- vertices errados!")
def __init__(self, u, v): self.origin = u self.dest = v self.twin = None self.face = None self.next_hedge = None self.segment = Segment(u.p, v.p) self.segment.lid = None u.hedge = self
def desenha (self): cima = self.sup.y baixo = max (self.a_esq.to.y, self.a_dir.to.y) # 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 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 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('green') self.aresta_baixo = (Segment (baixo_esq, baixo_dir)).plot('green') self.aresta_esq = (Segment (baixo_esq, cima_esq)).plot('green') self.aresta_dir = (Segment (baixo_dir, cima_dir)).plot('green')
def Generate(l): # Dado a lista de pontos do poligono e gera todos os segmentos de retas lsegments = [] n = len(l) if (n == 2): lsegments.append( SSegment(SPoint(l[0].x, l[0].y), SPoint(l[1].x, l[1].y))) seg = Segment(Point(l[0].x, l[0].y), Point(l[1].x, l[1].y)) seg.plot('green') control.sleep() else: for i in range(n): lsegments.append( SSegment(SPoint(l[i % n].x, l[i % n].y), SPoint(l[(i + 1) % n].x, l[(i + 1) % n].y))) seg = Segment(Point(l[i % n].x, l[i % n].y), Point(l[(i + 1) % n].x, l[(i + 1) % n].y)) seg.plot('green') control.sleep() return lsegments
def isDiagonal(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('blue') sleep() # Como o dentroDoPoligono é O(1) é muito prudente fazer esse teste primeiro result = dentroDoPoligono(u, w, P) and (not intersectaBorda(u, w, P)) uw.hide() return result
def read_segments(filename): if filename is None: raise ValueError("File name is None") with open(filename) as file: segments = set() for line in file: line = line.split() if len(line) != 4: raise ValueError("Invalid input from file: {}: {}".format( filename, line)) segments.add( Segment(Point(float(line[0]), float(line[1])), Point(float(line[2]), float(line[3])))) return segments
def read_intersections(filename): if filename is None: raise ValueError("File name is None") with open(filename) as file: intersections = {} point = None for line in file: line = line.split() if len(line) == 2: point = Point(float(line[0]), float(line[1])) intersections[point] = set() if len(line) == 4: intersections[point].add( Segment(Point(float(line[0]), float(line[1])), Point(float(line[2]), float(line[3])))) return intersections
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 min_par " global d blue = meio.hilight("blue") # desenha a faixa que eu estou procurando v1 = control.plot_vert_line(meio.x - d, "blue") v2 = control.plot_vert_line(meio.x + d, "blue") control.sleep() par_inter = None cand = candidatos(l, i, j, meio) for k in range(len(cand)): cyan = cand[k].hilight("cyan") 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("cyan") control.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 != None: par_inter.hide() par_inter = cand_inter par_inter.plot("blue") control.sleep() cand[k].unhilight(id=cyan) control.plot_delete(v1) control.plot_delete(v2) meio.unhilight(id=blue) control.sleep() return par_inter
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]) # 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 = control.plot_vert_line(meio.x) verde = meio.hilight() control.sleep() # Calcula o menor das duas metades par_esq = ShamosRec(l, i, q) par_dir = ShamosRec(l, q, j) par_min = minPar(par_esq, par_dir) # Intercala do mergeSort escondido intercalaY(l, i, j) control.plot_delete(vert_id) meio.unhilight(id=verde) # 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() par_esq.unhilight() par_dir.unhilight() global d dnovo = math.sqrt(dist(par_min)) d = min(d, dnovo) par_min.hilight("red") control.sleep() return par_min
def dentroDoPoligono(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("yellow") sleep() uw.hide() return resposta
def intersectaBorda(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('cyan') sleep() if (u not in aresta.endpoints()) and (w not in aresta.endpoints()): if (uw.intersects(aresta)): aresta.hide() aresta.plot('yellow') sleep() aresta.hide() return True aresta.hide() return False
def verticesVisiveis(p, poligs): pontos = [] for i in range(len(poligs)): pontos.extend(poligs[i].to_list()) compara = criaCompara(p) #Intersecta p.x -> inf+ T = Tree() pontos.sort(key=cmp_to_key(compara), reverse=True) for i in range(len(poligs)): listaPs = poligs[i].to_list() n = len(listaPs) for j in range(n): a = listaPs[j] b = listaPs[(j + 1) % n] if (passaEixoX(a, b, p)): if (left_on(p, b, a)): T.insert(Segment(a, b)) else: T.insert(Segment(b, a)) W = [] for i in range(len(pontos)): a = pontos[i] idBranco = p.lineto(a, 'white') a.hilight('yellow') control.sleep() a.hilight('red') a.unhilight() if (visivel(T, pontos, p, i)): if (a is not p): W.append(a) p.remove_lineto(a, idBranco) p.lineto(a, 'blue') else: continue else: p.remove_lineto(a, idBranco) b = a.prev c = a.next if (a.x == b.x and a.y == b.y): continue #a não está em um #polígono if (left_on(p, a, b)): T.delete(Segment(b, a)) if (left_on(p, a, c)): T.delete(Segment(c, a)) else: T.insert(Segment(a, c)) #else do primeiro if #Tentando evitar q na hora da inserção tenha segmentos terminando #na linha de varredura. if (right(p, a, b)): T.insert(Segment(a, b)) return W
def read(filename): """Reads any type of geometric primitive data structures (Point, Polygon, Segment) from a file and returns it as a list. This method reads geometric data from a file. Any empty line or any line started by '#' (considered a commentary) is ignored. The input can be mixed, it can contains a set of Polygons, Points and Segments and not necessarily only one type of data. The following patterns are required during the input operation: Point: defined by two floating point coordinates, on a line, separated by whitespaces. For example: 0 0 0.5 1.5 1.5 3 Polygon: defined by a list of adjacent points, enclosed by '[' at the beginning and ']' at the end, in the order that they appear in the polygon boundary, i.e., any pair of consecutive points defines an edge on the polygon boundary. For example, the following input defines a square: [ 0 0 1 0 1 1 0 1 ] Segment: defined by four floating point coordinates, on a line, separated by whitespaces. Each pair of consecutive coordinates defines a segment endpoint. For example, the following input defines a segment from (0, 0) to (0.5, 1.5): 0 0 0.5 1.5 Disc: Atualmente, ele espera que o arquivo contenha uma lista de discos, um disco por linha, as 3 coordenadas em cada linha (x, y, r). Exemplo: 0 0 0 0 1 2 10 100 50 :param filename: (str) The name of the file that will be read :return: (list) A list of geometric primitive data structures read from the file Raises: FileNotFoundError: if file could not be found TypeError: if 'filename' is None ValueError: if some input from the file does not follow the required patterns """ with open(filename) as file: i = 0 vertices = [] data = [] expecting_polygon = False for line in file: i += 1 line = line.split() if len(line) == 0 or line[0] == "#": continue if line[0] == "[": expecting_polygon = True elif line[0] == "]": expecting_polygon = False data.append(Polygon(vertices)) vertices = [] elif len(line) == 3: data.append(Disc(float(line[0]), float(line[1]), float(line[2]))) elif len(line) == 4: data.append( Segment( Point(float(line[0]), float(line[1])), Point(float(line[2]), float(line[3])) ) ) elif len(line) == 2: if expecting_polygon: vertices.append(Point(float(line[0]), float(line[1]))) else: data.append(Point(float(line[0]), float(line[1]))) else: raise ValueError( "Invalid input from file: {}: line: {}: {}".format(filename, i, line)) return data
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 = {}
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 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() no_p_min = Node_point(l[p_min]) faixa.deleta(no_p_min) p_min += 1 # Desenha o quadradinho de candidatos linha_frente = control.plot_vert_line(p.x) if i > 1: linha_tras = control.plot_vert_line(p.x - d, color="blue") 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("blue") linha_baixo.plot("blue") control.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: # Despinta das cores atuais, dai o dist2 pinta de amarelo, depois repinta de novo p.unhilight() vizinho.p.unhilight() d2 = dist2(p, vizinho.p) p.hilight() vizinho.p.hilight("blue") if d2 < d * d: d = d2**0.5 if par_min != None: par_min.hide() par_min = Segment(p, vizinho.p) par_min.plot("red") control.sleep() vizinho = faixa.sucessor(vizinho) # Depois com os vizinhos de baixo vizinho = faixa.predecessor(no_p) while vizinho != None and p.y - vizinho.p.y < d: # Despinta das cores atuais, dai o dist2 pinta de amarelo, depois repinta de novo p.unhilight() vizinho.p.unhilight() d2 = dist2(p, vizinho.p) p.hilight() vizinho.p.hilight("blue") if d2 < d * d: d = d2**0.5 if par_min != None: par_min.hide() par_min = Segment(p, vizinho.p) par_min.plot("red") control.sleep() vizinho = faixa.predecessor(vizinho) # Apaga o quadradinho control.plot_delete(linha_frente) if (i > 1): control.plot_delete(linha_tras) linha_cima.hide() linha_baixo.hide() p.unhilight() l[i].hilight("blue") "despinta quem sobrou na faixa" while (not faixa.vazia()): faixa.deleta_min().p.unhilight() par_min.hilight("red", "red")
def Monotono(p): # Essa é a forma que eu recebo o polígono do front-end :/ P = p[0] # lista com as diagonais, nosso return resp = [] v = ordenaY(P) n = len(v) s = [v[0], v[1]] # pilha v[0].hilight('blue') v[1].hilight('blue') t = 1 # index do fim da pilha for i in range(2, n): v[i].hilight('green') 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: a = s[t - 1] b = s[t] if a.x > b.x: a, b = b, a if right(a, b, v[i]): s[t].unhilight() s.pop() t -= 1 # acrescenta a nova diagonal d = Segment(s[t], v[i]) d.plot('green') sleep() resp.append(d) else: break t += 1 s.append(v[i]) v[i].unhilight() v[i].hilight('blue') elif vizinho_primeiro and not vizinho_ultimo: aux = s[t] while t > 0: # acrescenta a nova diagonal d = Segment(s[t], v[i]) d.plot('green') 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('blue') t = 1 else: while t > 1: s[t].unhilight() t -= 1 # acrescenta a nova diagonal d = Segment(s[t], v[i]) d.plot('green') sleep() resp.append(d) s[0].unhilight() s[1].unhilight() v[i].unhilight() return resp