예제 #1
0
    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
예제 #2
0
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
예제 #3
0
 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)
예제 #4
0
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)
예제 #5
0
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))
예제 #6
0
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
예제 #7
0
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]  # будем возвращать сначала верхний, а затем нижний
예제 #8
0
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
예제 #9
0
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
예제 #10
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]
예제 #11
0
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