def _iter_items(self, left=attrgetter("left"), right=attrgetter("right"), start_key=None, end_key=None): node = self._root stack = [] go_left = True in_range = self._get_in_range_func(start_key, end_key) while True: if left(node) is not None and go_left: stack.append(node) node = left(node) else: if in_range(node.key): yield node.key, node.value if right(node) is not None: node = right(node) go_left = True else: if not len(stack): return # all done node = stack.pop() go_left = False
def __angle(self, currentVertex, isTopNextOrder): stackBeforeTop = self.__stackBeforeTop() stackTop = self.__stackTop() if isTopNextOrder: return left(currentVertex.coordinates, stackTop.coordinates, stackBeforeTop.coordinates) return left(stackBeforeTop.coordinates, stackTop.coordinates, currentVertex.coordinates)
def diagonalInCone(self, firstVertex, secondVertex, diagonalEdge): i = self.vertexCoordinates(diagonalEdge[0]) j = self.vertexCoordinates(diagonalEdge[1]) u = self.vertexCoordinates(firstVertex) w = self.vertexCoordinates(secondVertex) if (left_on(u, i, w)): return left(i, j, u) and left(j, i, w) else: return not (left_on(i, j, w) and left_on(j, i, u))
def needs_fix(self, other): # inter are the edges self and other have in common inter, dif = self.get_relative_vertices(other) # check if quad is convex if (len(inter) != 2 or len(dif) != 2): print("ERRO NA LEGALIZACAO") exit(1) if self.v1 in inter: if self.v2 in inter: inter_0 = self.v1 inter_1 = self.v2 dif_0 = self.v3 else: inter_0 = self.v3 inter_1 = self.v1 dif_0 = self.v2 else: inter_0 = self.v2 inter_1 = self.v3 dif_0 = self.v1 if other.v1 in inter: if other.v2 in inter: dif_1 = other.v3 else: dif_1 = other.v2 else: dif_1 = other.v1 if not left(inter_0, inter_1, dif_1): aux = dif_0 dif_0 = dif_1 dif_1 = aux convex = left(inter_0, dif_0, inter_1) and\ left(dif_0, inter_1, dif_1) and\ left(inter_1, dif_1, inter_0) and\ left(dif_1, inter_0, dif_0) if not convex: return False # check if inter is best # only draws if passes convex self.draw("#ffaa33") other.draw("#ffaa33") did = control.plot_segment(inter_0.x, inter_0.y, inter_1.x,\ inter_1.y, color="#ffffff") control.sleep() control.plot_delete(did) self.remove_draw() other.remove_draw() C = Circle(inter_0, inter_1, dif_0) C.draw() control.sleep() C.remove_draw() return C.is_inside(dif_1)
def ilegal(e): " Devolve se a aresta dada pela meia aresta 'e' é ilegal " # As arestas do triangulão infinito não podem ser ilegais global infs if e.init in infs and e.to in infs: return False e.draw(color_legalizaveis) sleep() # O quadrilatero precisa ser convexo if left(e.twin.prox.to, e.to, e.prox.to) == left(e.twin.prox.to, e.init, e.prox.to): return False def angulo(p1, p2, p3): " Devolve algo proporcional ao angulo em p2 de p1-p2-p3 " # Na verdade, devolve o -2*cosseno do angulo com a lei do cosseno a2 = (p3.x - p1.x)**2 + (p3.y - p1.y)**2 b2 = (p3.x - p2.x)**2 + (p3.y - p2.y)**2 c2 = (p1.x - p2.x)**2 + (p1.y - p2.y)**2 ang = ((b2 + c2 - a2) / (2 * ((b2 * c2)**0.5))) return -ang # Como cosseno é descrescente para angulos menores que pi, # Então posso comparar dois angulos a e b pelos seus cossenos # a > b <=> cos(a) < cos(b) # Acha o menor angulo do triangulo com a aresta e min_ang1 = min([ angulo(e.prev.init, e.init, e.to), angulo(e.init, e.to, e.prev.init), angulo(e.to, e.prev.init, e.init) ]) # Acha o menor angulo do triangulo com a aresta e.twin min_ang2 = min([ angulo(e.twin.prev.init, e.init, e.to), angulo(e.init, e.to, e.twin.prev.init), angulo(e.init, e.twin.prev.init, e.to) ]) min_ang_legal = min(min_ang1, min_ang2) # Acha o menor angulo dos triangulos com a outra diagonal min_ang1 = min([ angulo(e.prev.init, e.init, e.twin.prev.init), angulo(e.init, e.prev.init, e.twin.prev.init), angulo(e.prev.init, e.twin.prev.init, e.init) ]) min_ang2 = min([ angulo(e.prev.init, e.to, e.twin.prev.init), angulo(e.to, e.prev.init, e.twin.prev.init), angulo(e.prev.init, e.twin.prev.init, e.to) ]) min_ang_ilegal = min(min_ang1, min_ang2) return min_ang_legal < min_ang_ilegal
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 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 cmp_sort_insertion_segments (a, b): "função de comparação para segmentos que compartilham a mesma\ ponta esquerda" if(prim.left(b.init, b.to, a.to)): return 1 else: return -1
def cmp_sort_remove_segments (a, b): "função de comparação para segmentos que compartilham a mesma\ ponta direita" if(prim.left(b.init, b.to, a.init)): return 1 else: return -1
def __init__(self, x, y, z): if left(x, z, y): #makes sure triangle in in counter-clockwise temp = z z = y y = temp self.v1 = x self.v2 = y self.v3 = z self.d_ids = []
def __gt__ (self, other): ref = other.ref # Se o ponto de referencia é uma interseção, if abs(area2 (self.seg.init, self.seg.to, ref)) < eps: # O ponto de referência vai ser o ponto da direita ref = other.seg.to # Self > other <=> other está a esquerda do self return left (self.seg.init, self.seg.to, ref)
def get_upper_segment(list0, interBST): "list0 é uma lista ordenada dos segmentos que contém o ponto\ evento como ponta esquerda e interBST é uma BST dos segmentos\ que contém o ponto evento em seu interior.\ Retorna o segmento mais acima dentre os elementos da lista e da BST." if(not interBST.isEmpty()): upper = interBST.max().key if (not list0 or not prim.left(upper.init, upper.to, list0[len(list0) - 1].to)): return upper return list0[len(list0) - 1]
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 get_lower_segment(list0, interBST): "list0 é uma lista ordenada dos segmentos que contém o ponto\ evento como ponta esquerda e interBST é uma BST dos segmentos\ que contém o ponto evento em seu interior.\ Retorna o segmento mais abaixo dentre os elementos da lista e da BST." if (not interBST.isEmpty()): lower = interBST.min().key if (not list0 or prim.left(lower.init, lower[0].to, list0[0].to)): return lower return list0[0]
def partition(points, start, end): pt_ind = extreme_point(points, start, end) swap(points, start + 1, pt_ind) part1 = part2 = end for i in range(end - 1, start + 1, -1): if prim.left(points[start], points[start + 1], points[i]): part1 -= 1 swap(points, part1, i) elif prim.left(points[start + 1], points[end], points[i]): part1 -= 1 part2 -= 1 swap(points, part2, i) if part1 != part2: swap(points, part1, i) part1 -= 1 part2 -= 1 swap(points, part2, start + 1) if part1 != part2: swap(points, part1, start + 1) part1 -= 1 swap(points, part1, start) return part1, part2
def particione (P, l, r): # 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])): P[i], P[l + 1] = P[l + 1], P[i] # Desenha o triangulo if hasattr(P[l + 1], 'hi'): P[l + 1].unhilight() P[l + 1].hilight("firebrick") linha_esq = P[l].lineto(P[l + 1], "green") linha_dir = P[r].lineto(P[l + 1], "red") sleep() p = q = r for k in range(r - 1, l + 1, -1): if hasattr(P[k], 'hi'): P[k].unhilight() P[k].hilight("yellow") sleep() P[k].unhilight() if left (P[l], P[l + 1], P[k]): # ponto da partição esquerda (verde) p -= 1 P[p], P[k] = P[k], P[p] P[p].hilight("green") sleep() elif right (P[r], P[l + 1], P[k]): # ponto da partição direita (vermelho) p -= 1 q -= 1 P[q], P[k] = P[k], P[q] if p != q: P[p], P[k] = P[k], P[p] P[q].hilight("red") sleep() # Ajustes finais no vetor p -= 1 q -= 1 P[q], P[l + 1] = P[l + 1], P[q] if p != q: P[p], P[l + 1] = P[l + 1], P[p] p -= 1 P[l], P[p] = P[p], P[l] return p, q, linha_esq, linha_dir
def _search(self, node, reference): if node is None: ret = None elif left(node.seg.init, node.seg.to, reference): ret = self._search(node.left, reference) elif right(node.seg.init, node.seg.to, reference): ret = self._search(node.right, reference) elif on_segment(node.seg.init, node.seg.to, reference): ret = node else: #already is collinear ret = self._search(node.right, reference) if ret is None: ret = self._search(node.left, reference) return ret
def trapContainsVertex(self, vertexPoint): if (self.topSuppVertex == vertexPoint): return True elif (vertexPoint == self.leftEdge[0]) or (vertexPoint == self.leftEdge[1]) or \ (vertexPoint == self.rightEdge[0]) or (vertexPoint == self.rightEdge[1]): return True elif (vertexPoint.y <= self.topSuppVertex.y) and \ ((vertexPoint.y <= self.leftEdge[0].y) and (vertexPoint.y >= self.leftEdge[1].y) and (vertexPoint.y <= self.rightEdge[0].y) and (vertexPoint.y >= self.rightEdge[1].y)) and \ (left_on(self.rightEdge[1].coordinates, self.rightEdge[0].coordinates, vertexPoint.coordinates) and not left(self.leftEdge[1].coordinates, self.leftEdge[0].coordinates, vertexPoint.coordinates)): return True return False
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 __caseTwo(self, BST, u, v, w): control.sleep() if (left(u.coordinates, v.coordinates, w.coordinates)): u, w = w, u trap = BST.getTrapAndRemove(v) if trap is None: leftEdge = [v, u] rightEdge = [v, w] newTrap = bst.Trap(leftEdge, v, rightEdge) BST.insert(newTrap) else: rightEdge = [v, u] newTrap = bst.Trap(trap.leftEdge, v, rightEdge) BST.insert(newTrap) leftEdge = [v, w] newTrap = bst.Trap(leftEdge, v, trap.rightEdge) BST.insert(newTrap) secLeftId = self.dcel.buildSegmentFromEdge(trap.leftEdge).hilight( color_line="blue", color_point="red") secRightId = self.dcel.buildSegmentFromEdge(trap.rightEdge).hilight( color_line="blue", color_point="red") x = trap.topSuppVertex xNumber = x.vertexNumber() vNumber = v.vertexNumber() diagonal = (xNumber, vNumber) self.dcel.addHalfEdge(diagonal) self.partitionDiagonalList.append([ (xNumber, vNumber), control.plot_segment(x.x, x.y, v.x, v.y, "yellow") ]) leftId = self.dcel.buildSegmentFromEdge(leftEdge).hilight( color_line="blue", color_point="red") rightId = self.dcel.buildSegmentFromEdge(rightEdge).hilight( color_line="blue", color_point="red") control.sleep() control.plot_delete(leftId) control.plot_delete(rightId) if (trap is not None): control.plot_delete(secLeftId) control.plot_delete(secRightId)
def __rightOnWrap(self, i, j, k): return not left(self.pointList[i], self.pointList[j], self.pointList[k])
def __gt__ (self, other): return left (self.a_esq.init, self.a_dir.to, other.sup)
def left (a, b, c): "retorna verdadeiro se c esta a esquerda do segmento ab" ret = prim.left (a, b, c) triang (a, b, c) return ret
def left(a, b, c): "retorna verdadeiro se c esta a esquerda do segmento ab" ret = prim.left(a, b, c) triang(a, b, c) return ret
def _pred_comp(self, seg, reference): return left(seg.init, seg.to, reference) or\ collinear(seg.init, seg.to, reference)
def _del_comp(self, seg1, seg2, reference): return left(seg1.init, seg1.to, reference) or\ (collinear(seg1.init, seg1.to, reference) and #if ties left(seg1.init, seg1.to, seg2.init)) # looks at starting point
def _ins_comp(self, seg1, seg2, reference): return left(seg1.init, seg1.to, reference) or\ (collinear(seg1.init, seg1.to, reference) and #if ties left(seg1.init, seg1.to, seg2.to)) # looks at endpoint
def contains_proper(self, pt): return left(self.v1, self.v2, pt) and\ left(self.v2, self.v3, pt) and\ left(self.v3, self.v1, pt)
def compare_to (self, a, b): if(prim.left(b.init, b.to, a.to)): return 1 elif (prim.left_on(b.init, b.to, a.to)): return 0 return -1