def intersects(self, other): """ пересечение отрезка с другим отрезком :param other: экземпляр Segment :return: Point точка пересечения или None, если пересечения нет """ a, b = normalize(self.start), normalize(self.end) c, d = normalize(other.start), normalize(other.end) if (a == c) and (b == d): return None acd, bcd = turn(a, c, d), turn(b, c, d) cab, dab = turn(c, a, b), turn(d, a, b) do_intersect = False if acd == bcd == cab == dab == 0: do_intersect = (a <= c <= b or a <= d <= b or c <= a <= d or c <= b <= d) else: do_intersect = acd != bcd and cab != dab if do_intersect: cross = lambda a, b: np.cross([a.coord], [b.coord]) prod = np.cross(cross(a, b), cross(c, d))[0] if (prod[0] == 0 and prod[1] == 0 and prod[2] == 0): return max(b, d) return normalize(Point(prod, homogeneous=True)) return None
def compute_vtype_answer(v1, v2, v3): if v1 > v2 and v3 > v2: # greater means below if turn(v1, v2, v3) > 0: return VType.start else: return VType.split elif v1 < v2 and v3 < v2: if turn(v1, v2, v3) > 0: return VType.end else: return VType.merge return VType.regular
def visit(self, s): # Порядок обхода задает предикат поворота sign = turn(s.p, self.segment.p, self.segment.q) if sign != 0: return self.left.visit(s) if sign == 1 else self.right.visit(s) else: # У отрезков общая левая точка, надо проверить поворот по правой точке отрезка assert self.segment.p == s.p assert not self.segment.q == s.q sign = turn(s.q, self.segment.p, self.segment.q) if sign == 0: raise Exception('Error') return self.left.visit(s) if sign == 1 else self.right.visit(s)
def correct_comparator(a, b): first = turn(a[0], a[1], b[0]) second = turn(a[0], a[1], b[1]) if first * second == 1: if turn(a[0], a[1], b[0]) < 0: return True else: return False elif first * second == 0: if first < 0 or second < 0: return True else: return False else: return not correct_comparator(b, a)
def intersect_segments(a, b): if turn(a[0], a[1], b[0]) * turn(a[0], a[1], b[1]) == 1: return False if turn(b[0], b[1], a[0]) * turn(b[0], b[1], a[1]) == 1: return False x1, y1 = a[0].coord[0], a[0].coord[1] x2, y2 = a[1].coord[0], a[1].coord[1] x3, y3 = b[0].coord[0], b[0].coord[1] x4, y4 = b[1].coord[0], b[1].coord[1] xx1 = [min(x1, x2), max(x1, x2)] xx2 = [min(x3, x4), max(x3, x4)] yy1 = [min(y1, y2), max(y1, y2)] yy2 = [min(y3, y4), max(y3, y4)] return (overlap(xx1, xx2) or overlap(xx2, xx1)) and (overlap(yy1, yy2) or pverlap(yy2, yy1))
def walk_along(p: Vertex, q: Point) -> Iterator: is_last_point = True intersected = p while True: if is_last_point: prev = -2 for prev_face, curr_face in look_back(walk_around(intersected)): a, _ = curr_face.rest(intersected) curr = turn(intersected.geometry, q, a.geometry) if curr != prev: if curr >= 0: is_last_point = curr == 0 intersected = prev_face break prev = curr else: yield intersected if not all(map(methodcaller('is_finite'), intersected.vertices)): break turns = [ turn(p.geometry, q, vertex.geometry) for vertex in intersected.vertices ] for i in range(3): if turns[i] == 0 and p != intersected.vertices[i]: intersected = intersected.vertices[i] is_last_point = True i -= 1 break if i < 2: continue for i in range(3): if p == intersected.vertices[i]: continue if turns[i] != turns[Face.ccw(i)] and turns[Face.ccw(i)] == 1: intersected = intersected.neighbours[Face.cw(i)] break
def left_insert(tmap, s, parent): """Метод для вставки отрезка в самый левый трапецоид. Отрезок пересекает как минимум 2 трапецоида""" assert s.p != parent.rightp # отрезок не должен был попасть в этот трапецоид up = Trapezoid(parent.top, s, s.p, parent.rightp) down = Trapezoid(s, parent.bottom, s.p, parent.rightp) # одна из rightp ещё не известна left = Trapezoid(parent.top, parent.bottom, parent.leftp, s.p) tmap.tr += [up, down, left] up.leftnb = [left, None] down.leftnb = [None, left] left.leftnb = parent.leftnb left.rightnb = [up, down] update_left_nb(parent, left, [0, 1]) sign = turn(parent.rightp, s.p, s.q) if sign == 1: # точка выше отрезка, нижний трапецоид не закончен down.rightp = None up.rightnb = [parent.rightnb[0], None] # нижний не известен update_right_nb(parent, up, [0]) elif sign == -1: # точка ниже отрезка, верхний трапецоид не закончен up.rightp = None down.rightnb = [None, parent.rightnb[1]] update_right_nb(parent, down, [1]) else: # отрезок попал в rightp assert parent.rightp == s.q up.rightnb = [parent.rightnb[0], None] down.rightnb = [None, parent.rightnb[1]] if parent.rightnb[0] is not None: assert parent.rightnb[0].leftnb[0] == parent parent.rightnb[0].leftnb[0] = up if parent.rightnb[1] is not None: assert parent.rightnb[1].leftnb[1] == parent parent.rightnb[1].leftnb[1] = down # Строим новое поддерево up_node = TrapezoidNode(up) down_node = TrapezoidNode(down) left_node = TrapezoidNode(left) segment_node = YNode(s, up_node, down_node) p_node = XNode(s.p, left_node, segment_node) # Обновим ссылки между узлами и трапецоидами up_node.links.append(segment_node) down_node.links.append(segment_node) left_node.links.append(p_node) update_node_links(parent.node, p_node) tmap.tr.remove(parent) return [up, down] # будем возвращать сначала верхний, а затем нижний
def intersect_segment(s: Segment, left_tr: Trapezoid): """Возвращает список трапецоидов, которые пересекает отрезок""" while not left_tr.is_rightmost(): # Поиск остановится, если у трапецоида нет соседей справа или конец отрезка внутри трапецоида. if s.q <= left_tr.rightp: break else: # Надо понять, в какого соседа пойдет отрезок. Считаем поворот rightp относительно прямой s sign = turn(left_tr.rightp, s.p, s.q) if sign == 1: # Отрезок пересекает нижнего соседа left_tr = left_tr.rightnb[1] elif sign == -1: # Отрезок пересекает верхнего соседа left_tr = left_tr.rightnb[0] else: # sign == 0 # Отрезок касается вершины внутренней точкой, такой отрезок не подходит под условие! raise Exception('Error') assert left_tr is not None yield left_tr
def comparator_answer(a, b, c, d): x = turn(a, b, c) * turn(a, b, d) if x > 0: # один знак return turn(a, b, c) > 0 else: # мы точно знаем, что они не пересекаются, поэтому, если одна тройка будет разных знаков, то другая - нет return turn(c, d, b) < 0
def segment_insert(tmap, s, parent, left_tr): """Вставка отрезка в очередной трапецоид, возможно последний""" # Либо верхний, либо нижний трапецоид недоделан, либо начало отрезка совпало с точкой другого отрезка # Определим это по левым соседям трапецоида if left_tr[0] is not None and left_tr[0].rightp is None: assert left_tr[1].rightp is not None and parent.leftp == left_tr[ 1].rightp # новый трапецоид - нижний; верхний недоделан up = left_tr[0] down = Trapezoid(s, parent.bottom, parent.leftp, parent.rightp) tmap.tr += [down] left_tr[1].rightnb[0] = down down.leftnb = [left_tr[1], parent.leftnb[1]] update_left_nb(parent, down, [1]) up_node = up.node down_node = TrapezoidNode(down) elif left_tr[1] is not None and left_tr[1].rightp is None: assert left_tr[0].rightp is not None and parent.leftp == left_tr[ 0].rightp # новый трапецоид - верхний, а нижний недоделан down = left_tr[1] up = Trapezoid(parent.top, s, parent.leftp, parent.rightp) tmap.tr += [up] left_tr[0].rightnb[1] = up up.leftnb = [parent.leftnb[0], left_tr[0]] update_left_nb(parent, up, [0]) up_node = TrapezoidNode(up) down_node = down.node else: # s.p совпадает с leftp assert parent.leftp == s.p up = Trapezoid(parent.top, s, parent.leftp, parent.rightp) down = Trapezoid(s, parent.bottom, parent.leftp, parent.rightp) tmap.tr += [up, down] if parent.leftnb[0] is not None: up.leftnb = [parent.leftnb[0], None] update_left_nb(parent, up, [0]) else: up.leftnb = [None, None] if parent.leftnb[1] is not None: down.leftnb = [None, parent.leftnb[1]] update_left_nb(parent, down, [1]) else: down.leftnb = [None, None] up_node = TrapezoidNode(up) down_node = TrapezoidNode(down) # Надо понять, верхний или нижний трапецоид продлевать assert not parent.is_rightmost() # не должны здесь оказаться sign = turn(parent.rightp, s.p, s.q) if sign == 1: # точка выше отрезка, нижний трапецоид не закончен down.rightp = None up.rightp = parent.rightp # если в прошлый раз не закончили его up.rightnb = [parent.rightnb[0], None] update_right_nb(parent, up, [0]) elif sign == -1: # точка ниже отрезка, верхний трапецоид не закончен up.rightp = None down.rightp = parent.rightp # если в прошлый раз не закончили его down.rightnb = [None, parent.rightnb[1]] update_right_nb(parent, down, [1]) else: # отрезок попал в вершину, значит это последний трапецоид assert parent.rightp == s.q up.rightnb = [parent.rightnb[0], None] down.rightnb = [None, parent.rightnb[1]] up.rightp = parent.rightp down.rightp = parent.rightp segment_node = YNode(s, up_node, down_node) up_node.links.append(segment_node) down_node.links.append(segment_node) update_node_links(parent.node, segment_node) tmap.tr.remove(parent) return [up, down]
def is_inside(triangle, point): for i in range(3): if turn(triangle[i], triangle[(i + 1) % 3], point) * turn(triangle[i], triangle[(i + 1) % 3], triangle[(i + 2) % 3]) < 0: return False return True