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 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 intersection(self, other): "Retorna uma lista com o(s) ponto(s) de interseção entre os dois círculos" if not self.intersects_circ(other): return [] # Um pouco de geometria: Montando a esquação do circulo # Temos: self: (x - x1)^2 + (y - y1)^2 = r1^2 # other: (x - x2)^2 + (y - y2)^2 = r2^2 x1, y1 = self.center.x, self.center.y x2, y2 = other.center.x, other.center.y r1, r2 = self.r, other.r # Depois de subtrair as duas equações, teremos uma reta # 2x*(x2 - x1) + 2y*(y2 - y1) + x1^2 - x2^2 + y1^2 - y2^2 = r1^2 - r2^2 # Isolando o x para a resposta, temos essa grande conta: # x = [ r1^2 - r2^2 + x2^2 - x1^2 + y2^2 - x1^2 + 2y*(y2 - y1) ] / 2*(x2 - x1) # se x1 = x2, temos um caso mais simples, basta encontrar y if x1 == x2: if y1 == y2: # supondo que não há circulos iguais return [] res_y1 = (r1**2 - r2**2 + y2**2 - y1**2) / (2 * (y2 - y1)) res_y2 = res_y1 res_x1 = (r1**2 - (res_y1 - y1)**2)**(0.5) + x1 res_x2 = -(r1**2 - (res_y1 - y1)**2)**(0.5) + x1 # Se não, temos que colocar o x em alguma das equações dos circulos e criar uma equação de 2º grau # Depois de (( muitas )) continhas ... # conclui que os valores de a, b e c para nossa equação ay^2 + by + c = 0 são else: const = r1**2 - r2**2 + y2**2 - y1**2 + x2**2 + x1**2 - 2 * x1 * x2 a = (y1 - y2)**2 / (x1 - x2)**2 + 1 b = (y1 - y2) * const / (x1 - x2)**2 - 2 * y1 c = const**2 / (4 * (x1 - x2)**2) + y1**2 - r1**2 # Agora a gente aplica um super bhaskara delta = b**2 - 4 * a * c res_y1 = (-b + delta**(0.5)) / (2 * a) res_y2 = (-b - delta**(0.5)) / (2 * a) # Aplica os valores na reta para descobir os x res_x1 = (r1**2 - r2**2 + y2**2 - y1**2 + x2**2 - x1**2 + 2 * res_y1 * (y1 - y2)) / (2 * (x2 - x1)) res_x2 = (r1**2 - r2**2 + y2**2 - y1**2 + x2**2 - x1**2 + 2 * res_y2 * (y1 - y2)) / (2 * (x2 - x1)) p1 = Point(res_x1, res_y1) p2 = Point(res_x2, res_y2) if p1.approx_equals(p2): return [p1] return [p1, p2]
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 pontos_infinitos (p): " Devolve três pontos fictícios tais que o triangulo formado por eles " " contém todos os pontos de p " # Vou montar um quadradão que contém todos os pontos cima = baixo = direito = esquerdo = p[0] for i in range(1, len(p)): if p[i].y > cima.y: cima = p[i] if p[i].y < baixo.y: baixo = p[i] if p[i].x < esquerdo.x: esquerdo = p[i] if p[i].x > direito.x: direito = p[i] # Agora monto um triângulão que contém esse quadrado p1 = Point (esquerdo.x - 10*(direito.x - esquerdo.x), baixo.y - 10*(cima.y - baixo.y)) p2 = Point (esquerdo.x + (direito.x - esquerdo.x)/2, cima.y + 10*(cima.y - baixo.y)) p3 = Point (esquerdo.x + 10*(direito.x - esquerdo.x), baixo.y - 10*(cima.y - baixo.y)) return p1, p2, p3
def main (): novo = [] clara = [] for i in randdisc(150, 60): novo.append(Point(i[0] + 300, i[1] + 392)) for i in uniform_circ(25, 90): novo.append(Point(i[0] + 300, i[1] + 392)) for i in uniform_circ(50, 110): novo.append(Point(i[0] + 300, i[1] + 392)) for i in grid(15, 15): novo.append(Point(i[0], i[1])) clara.append(Point(i[0], i[1])) f = open('input/pontos/gema', "w") for p in novo: f.write ('%f %f\n' % (p.x, p.y - 92)) f.close() return clara, novo
def orelhas(poligono): """ Algoritmo que usa a estratégia de encontrar e remover orelhas para triangular o polígono """ # Cria uma cópia pra não zoar o input original novo = [] for p in poligono.vertices(): novo.append(Point(p.x, p.y)) P = Polygon(novo) n = len(P.vertices()) # Dicionario que relaciona os vértices a um booleano que indica se é orelha # Aproveitando que os pontos são 'hashables' orelha = dict() #PreProcessamento dos vértices v = P.pts orelha[v] = is_orelha(v, P) v = v.next while v != P.pts: orelha[v] = is_orelha(v, P) v = v.next while n > 3: # Procura uma orelha while not orelha[v]: v = v.next # Sinaliza qual orelha eu escolhi v.hilight('firebrick') # Desenha a diagonal e desmarca a orelha v.prev.lineto(v.next, 'orange') orelha[v] = False sleep() # Tira v do polígono u = v.prev w = v.next w.prev = u u.next = w # Essa parte é pra lista sempre ficar circular # (P.pts podia ficar inacessivel dai o algoritmo entrava em loop) if v == P.pts: P.pts = P.pts.next # Confere se não criei nenhuma orelha orelha[u] = is_orelha(u, P) orelha[w] = is_orelha(w, P) v.unhilight() n -= 1 # Despinta alguma orelha que tenha sobrado while not orelha[v]: v = v.next v.unhilight()
def eventos(circulos): "Função que retorna uma ABBB de pontos-eventos, que são os extremos horizontais dos circulos" Q = Abbb() # Abbb dos pontos eventos for c in circulos: p_esq = c.center - Point(c.r, 0) p_dir = c.center + Point(c.r, 0) baixo = Node_Semi_Circle(c, True, p_esq) cima = Node_Semi_Circle(c, False, p_esq) p1 = Node_Point_Circle(p_esq, ini=[baixo, cima], fim=[], inter=[], inter_unico=[]) p2 = Node_Point_Circle(p_dir, ini=[], fim=[baixo, cima], inter=[], inter_unico=[]) no1 = Q.busca(p1) no2 = Q.busca(p2) # Se os pontos já estão inseridos, só atualiza, se não, insere if no1.elemento != None: no1.elemento.ini.append(baixo) no1.elemento.ini.append(cima) else: Q.insere(p1) p_esq.plot('red') no1 = Q.busca(p1) if no2.elemento != None: no2.elemento.fim.append(baixo) no2.elemento.fim.append(cima) else: Q.insere(p2) p_dir.plot('red') return Q
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 randomPolygon(ctrX, ctrY, aveRadius, irregularity, spikeyness, numVerts): ''' Start with the centre of the polygon at ctrX, ctrY, then creates the polygon by sampling points on a circle around the centre. Randon noise is added by varying the angular spacing between sequential points, and by varying the radial distance of each point from the centre. Params: ctrX, ctrY - coordinates of the "centre" of the polygon aveRadius - in px, the average radius of this polygon, this roughly controls how large the polygon is, really only useful for order of magnitude. irregularity - [0,1] indicating how much variance there is in the angular spacing of vertices. [0,1] will map to [0, 2pi/numberOfVerts] spikeyness - [0,1] indicating how much variance there is in each vertex from the circle of radius aveRadius. [0,1] will map to [0, aveRadius] numVerts - self-explanatory Returns a list of vertices, in CCW order. ''' irregularity = clip(irregularity, 0, 1) * 2 * math.pi / numVerts spikeyness = clip(spikeyness, 0, 1) * aveRadius # generate n angle steps angleSteps = [] lower = (2 * math.pi / numVerts) - irregularity upper = (2 * math.pi / numVerts) + irregularity sum = 0 for i in range(numVerts): tmp = uniform(lower, upper) angleSteps.append(tmp) sum = sum + tmp # normalize the steps so that point 0 and point n+1 are the same k = sum / (2 * math.pi) for i in range(numVerts): angleSteps[i] = angleSteps[i] / k # now generate the points points = [] angle = uniform(0, 2 * math.pi) for i in range(numVerts): r_i = clip(gauss(aveRadius, spikeyness), 0, 2 * aveRadius) x = ctrX + r_i * math.cos(angle) y = ctrY + r_i * math.sin(angle) points.append(Point(int(x), int(y))) angle = angle + angleSteps[i] return points
def intersection(self, other_segment): "Retorna o ponto de interseção entre as duas retas se existir" if not self.intersects(other_segment): return None # um pouco de geometria, montando e igualando as equações das retas x0, y0 = self.init.x, self.init.y x1, y1 = self.to.x, self.to.y x2, y2 = other_segment.init.x, other_segment.init.y x3, y3 = other_segment.to.x, other_segment.to.y # r1 : a1x + b1y = c1 a1 = y0 - y1 b1 = x1 - x0 c1 = x0 * y1 - x1 * y0 # r2: a2x + b2y = c2 a2 = y2 - y3 b2 = x3 - x2 c2 = x2 * y3 - x3 * y2 # Resposta do sistema linear x = (b1 * c2 - b2 * c1) / (a1 * b2 - a2 * b1) y = (a2 * c1 - a1 * c2) / (a1 * b2 - a2 * b1) return Point(x, y)
def lee_preparata(poligono): # Cria uma cópia pra não zoar o input original novo = [] for p in poligono.vertices(): novo.append(Point(p.x, p.y)) P = Polygon(novo) diags = [] d = Dcel() d.init_polygon(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('green') desenhos.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("orange")
def __gt__(self, other): if self.circ == other.circ: return self.baixo and not other.baixo ref = other.ref x = self.circ.center.x y = self.circ.center.y # Se o ponto de referencia é uma interseção, if abs((ref.x - x)**2 + (ref.y - y)**2 - self.circ.r**2) < eps: # então eu pego um ponto um pouco posterior pra ser o ponto de refencia, # aplicando a formula do circulo pra 2*epsilon pra frente if other.baixo: sinal = -1 else: sinal = 1 # Formula do circulo x_novo = ref.x + 2 * eps x_novo = min(x_novo, other.circ.center.x + other.circ.r) y_novo = other.circ.center.y y_novo += sinal * (other.circ.r**2 - (x_novo - other.circ.center.x)**2)**0.5 ref = Point(x_novo, y_novo) # Self > other <=> other está a esquerda do self return self.esquerda(ref, other.baixo)
def extremes(self): offsets = [self.r, -self.r] return [self.center + Point(0, off) for off in offsets ] + [self.center + Point(off, 0) for off in offsets]
def escreve_algorithms(): a = [Point (315, 50), Point (319, 60), Point (331, 60), Point (319, 60), Point (323, 70), Point (327, 70), Point (335, 50)] for i in range(1, len(a)): a[i].lineto(a[i - 1], 'orange') sleep() l = [Point (339, 66), Point (339, 50), Point (352, 50)] for i in range(1, len(l)): l[i].lineto(l[i - 1], 'orange') sleep() g = [Point (370, 66), Point (356, 66), Point (356, 50), Point (370, 50), Point (370, 58), Point (364, 58)] for i in range(1, len(g)): g[i].lineto(g[i - 1], 'orange') sleep() o = [Point (374, 50), Point (374, 66), Point (387, 66), Point (387, 50)] for i in range(len(o)): o[i].lineto(o[i - 1], 'orange') sleep() r = [Point (392, 50), Point (392, 66), Point (408, 66), Point (408, 58), Point (398, 58), Point (408, 50)] for i in range(1, len(r)): r[i].lineto(r[i - 1], 'orange') sleep() i = [Point (413, 50), Point (426, 50), Point (419, 50), Point (419, 66), Point (426, 66), Point (413, 66)] for j in range(1, len(i)): i[j].lineto(i[j - 1], 'orange') sleep() t = [Point (438, 50), Point (438, 66), Point (430, 66), Point (446, 66)] for i in range(1, len(t)): t[i].lineto(t[i - 1], 'orange') sleep() h = [Point (451, 50), Point (451, 66), Point(451, 58), Point (465, 58), Point (465, 50), Point (465, 66)] for i in range(1, len(h)): h[i].lineto(h[i - 1], 'orange') sleep() m = [Point (470, 50), Point (470, 66), Point (478, 58), Point (486, 66), Point(486, 50)] for i in range(1, len(m)): m[i].lineto(m[i - 1], 'orange') sleep() s = [Point (507, 66), Point (491, 66), Point (491, 58), Point (507, 58), Point (507, 50), Point (491, 50)] for i in range(1, len(s)): s[i].lineto(s[i - 1], 'orange') sleep()
def escreve_geometric(): g = [Point (130, 70), Point (110, 70), Point (110, 50), Point (130, 50), Point (130, 60), Point (120, 60)] for i in range(1, len(g)): g[i].lineto(g[i - 1], 'orange') sleep() e = [Point (151, 50), Point (135, 50), Point (135, 58), Point (151, 58), Point (135, 58), Point (135, 66), Point (151, 66)] for i in range(1, len(e)): e[i].lineto(e[i - 1], 'orange') sleep() o = [Point (156, 50), Point (156, 66), Point (172, 66), Point (172, 50)] for i in range(len(o)): o[i].lineto(o[i - 1], 'orange') sleep() m = [Point (177, 50), Point (177, 66), Point (185, 58), Point (193, 66), Point(193, 50)] for i in range(1, len(m)): m[i].lineto(m[i - 1], 'orange') sleep() e = [Point (214, 50), Point (198, 50), Point (198, 58), Point (214, 58), Point (198, 58), Point (198, 66), Point (214, 66)] for i in range(1, len(e)): e[i].lineto(e[i - 1], 'orange') sleep() t = [Point (224, 50), Point (224, 66), Point (216, 66), Point (231, 66)] for i in range(1, len(t)): t[i].lineto(t[i - 1], 'orange') sleep() r = [Point (233, 50), Point (233, 66), Point (247, 66), Point (247, 58), Point (237, 58), Point (247, 50)] for i in range(1, len(r)): r[i].lineto(r[i - 1], 'orange') sleep() i = [Point (252, 50), Point (264, 50), Point (258, 50), Point (258, 66), Point (252, 66), Point (264, 66)] for j in range(1, len(i)): i[j].lineto(i[j - 1], 'orange') sleep() c = [Point (285, 50), Point (269, 50), Point (269, 66), Point (285, 66)] for i in range(1, len(c)): c[i].lineto(c[i - 1], 'orange') sleep()
def escreve_gema(): g = [Point (210, 190), Point (140, 190), Point (140, 110), Point (210, 110), Point (210, 150), Point (190, 150)] for i in range(len(g)): g[i].hilight() if (i > 0): g[i].lineto(g[i - 1], 'orange') sleep() e = [Point (290, 110), Point (230, 110), Point (230, 150), Point (290, 150), Point (230, 150), Point (230, 180), Point (290, 180)] for i in range(len(e)): e[i].hilight() if (i > 0): e[i].lineto(e[i - 1], 'orange') sleep() m = [Point (310, 110), Point (310, 180), Point (340, 150), Point (370, 180), Point(370, 110)] for i in range(len(m)): m[i].hilight() if (i > 0): m[i].lineto(m[i - 1], 'orange') sleep() a = [Point (390, 110), Point (405, 150), Point (445, 150), Point (405, 150), Point (420, 190), Point (430, 190), Point (460, 110)] for i in range(len(a)): a[i].hilight() if (i > 0): a[i].lineto(a[i - 1], 'orange') sleep()
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')