コード例 #1
0
def test_step(context: Context, contour: Contour) -> None:
    first_vertex, rest_contour = pop_left_vertex(contour)
    rest_vertices = rest_contour.vertices

    result = contour_self_intersects(rest_contour)
    next_result = contour_self_intersects(contour)

    first_edge = context.segment_cls(first_vertex, rest_vertices[0])
    last_edge = context.segment_cls(rest_vertices[-1], first_vertex)
    rest_edges = contour_to_edges(rest_contour)
    overlap_relations = (Relation.COMPONENT, Relation.COMPOSITE,
                         Relation.EQUAL, Relation.OVERLAP)
    assert (next_result is (result and len(rest_vertices) > 2 and (any(
        context.segments_relation(rest_edges[index], rest_edges[other_index])
        is not Relation.DISJOINT for index in range(len(rest_edges) - 1)
        for other_index in chain(range(index -
                                       1), range(index + 2,
                                                 len(rest_edges) - 1))
    ) or any(
        context.segments_relation(edge, other_edge) in overlap_relations
        for edge, other_edge in combinations(rest_edges[:-1], 2)
    )) or any(
        context.segments_relation(first_edge, edge) is not Relation.DISJOINT
        for edge in rest_edges[1:-1]) or any(
            context.segments_relation(last_edge, edge) is not Relation.DISJOINT
            for edge in rest_edges[:-2]) or len(rest_vertices) > 1 and (
                context.segments_relation(first_edge, rest_edges[0])
                in overlap_relations or context.segments_relation(
                    first_edge, last_edge) in overlap_relations
                or context.segments_relation(
                    last_edge, rest_edges[0]) in overlap_relations)))
コード例 #2
0
ファイル: linear.py プロジェクト: lycantropos/clipping
def _symmetric_subtract_segments_overlap(minuend: Segment,
                                         subtrahend: Segment,
                                         context: Context) -> Multisegment:
    left_start, left_end, right_start, right_end = sorted([
        minuend.start, minuend.end, subtrahend.start, subtrahend.end])
    return context.multisegment_cls([context.segment_cls(left_start, left_end),
                                     context.segment_cls(right_start,
                                                         right_end)])
コード例 #3
0
ファイル: linear.py プロジェクト: lycantropos/clipping
def _subtract_segments_overlap(minuend: Segment,
                               subtrahend: Segment,
                               context: Context) -> Segment:
    left_start, left_end, right_start, right_end = sorted([
        minuend.start, minuend.end, subtrahend.start, subtrahend.end])
    return (context.segment_cls(left_start, left_end)
            if left_start == minuend.start or left_start == minuend.end
            else context.segment_cls(right_start, right_end))
コード例 #4
0
ファイル: region.py プロジェクト: lycantropos/orient
def _relate_segment_to_contour(contour: Contour, segment: Segment,
                               context: Context) -> Relation:
    # similar to segment-in-contour check
    # but cross has higher priority over overlap
    # because cross with contour will be considered as cross with region
    # whereas overlap with contour can't be an overlap with region
    # and should be classified by further analysis
    has_no_touch = has_no_overlap = True
    last_touched_edge_index = last_touched_edge_start = None
    start, end = segment.start, segment.end
    for index, edge in enumerate(context.contour_segments(contour)):
        edge_start, edge_end = edge_endpoints = edge.start, edge.end
        relation_with_edge = relate_segments(edge, segment, context)
        if (relation_with_edge is Relation.COMPONENT
                or relation_with_edge is Relation.EQUAL):
            return Relation.COMPONENT
        elif (relation_with_edge is Relation.OVERLAP
              or relation_with_edge is Relation.COMPOSITE):
            if has_no_overlap:
                has_no_overlap = False
        elif relation_with_edge is Relation.TOUCH:
            if has_no_touch:
                has_no_touch = False
            elif (index - last_touched_edge_index == 1
                  and start not in edge_endpoints
                  and end not in edge_endpoints and (context.angle_orientation(
                      start, end, edge_start) is Orientation.COLLINEAR)
                  and point_vertex_line_divides_angle(
                      start, last_touched_edge_start, edge_start, edge_end,
                      context)):
                return Relation.CROSS
            last_touched_edge_index = index
            last_touched_edge_start = edge_start
        elif relation_with_edge is Relation.CROSS:
            return Relation.CROSS
    vertices = contour.vertices
    if not has_no_touch and last_touched_edge_index == len(vertices) - 1:
        first_edge_endpoints = first_edge_start, first_edge_end = (
            vertices[-1], vertices[0])
        if (relate_segments(
                context.segment_cls(first_edge_start, first_edge_end), segment,
                context) is Relation.TOUCH
                and start not in first_edge_endpoints
                and end not in first_edge_endpoints
                and (context.angle_orientation(start, end, first_edge_start) is
                     Orientation.COLLINEAR)
                and point_vertex_line_divides_angle(
                    start, vertices[-2], first_edge_start, first_edge_end,
                    context)):
            return Relation.CROSS
    return ((Relation.DISJOINT if has_no_touch else Relation.TOUCH)
            if has_no_overlap else Relation.OVERLAP)
コード例 #5
0
def relate_segment(contour: Contour, segment: Segment,
                   context: Context) -> Relation:
    angle_orientation = context.angle_orientation
    has_no_touch = has_no_cross = True
    last_touched_edge_index = last_touched_edge_start = None
    start, end = segment.start, segment.end
    for index, sub_segment in enumerate(context.contour_segments(contour)):
        sub_segment_start, sub_segment_end = sub_segment_endpoints = (
            sub_segment.start, sub_segment.end)
        relation = relate_segments(sub_segment, segment, context)
        if relation is Relation.COMPONENT or relation is Relation.EQUAL:
            return Relation.COMPONENT
        elif relation is Relation.OVERLAP or relation is Relation.COMPOSITE:
            return Relation.OVERLAP
        elif relation is Relation.TOUCH:
            if has_no_touch:
                has_no_touch = False
            elif (has_no_cross and index - last_touched_edge_index == 1
                  and start not in sub_segment_endpoints
                  and end not in sub_segment_endpoints and (angle_orientation(
                      start, end, sub_segment_start) is Orientation.COLLINEAR)
                  and point_vertex_line_divides_angle(
                      start, last_touched_edge_start, sub_segment_start,
                      sub_segment_end, context)):
                has_no_cross = False
            last_touched_edge_index = index
            last_touched_edge_start = sub_segment_start
        elif has_no_cross and relation is Relation.CROSS:
            has_no_cross = False
    vertices = contour.vertices
    if (has_no_cross and not has_no_touch
            and last_touched_edge_index == len(vertices) - 1):
        first_sub_segment_endpoints = (first_sub_segment_start,
                                       first_sub_segment_end) = (vertices[-1],
                                                                 vertices[0])
        if (relate_segments(
                context.segment_cls(first_sub_segment_start,
                                    first_sub_segment_end), segment, context)
                is Relation.TOUCH and start not in first_sub_segment_endpoints
                and end not in first_sub_segment_endpoints
                and (angle_orientation(start, end, first_sub_segment_start) is
                     Orientation.COLLINEAR)
                and point_vertex_line_divides_angle(
                    start, vertices[-2], first_sub_segment_start,
                    first_sub_segment_end, context)):
            has_no_cross = False
    return ((Relation.DISJOINT if has_no_touch else Relation.TOUCH)
            if has_no_cross else Relation.CROSS)
コード例 #6
0
ファイル: linear.py プロジェクト: lycantropos/clipping
def _unite_segments_touch(first: Segment,
                          second: Segment,
                          context: Context) -> Union_[Multisegment, Segment]:
    return (context.multisegment_cls([first, second])
            if ((first.start != second.start
                 or (context.angle_orientation(first.start, first.end,
                                               second.end)
                     is not Orientation.COLLINEAR))
                and (first.start != second.end
                     or (context.angle_orientation(first.start, first.end,
                                                   second.start)
                         is not Orientation.COLLINEAR))
                and (first.end != second.start
                     or (context.angle_orientation(first.end, first.start,
                                                   second.end)
                         is not Orientation.COLLINEAR))
                and (first.end != second.end
                     or (context.angle_orientation(first.end, first.start,
                                                   second.start)
                         is not Orientation.COLLINEAR)))
            else context.segment_cls(min(first.start, first.end,
                                         second.start, second.end),
                                     max(first.start, first.end,
                                         second.start, second.end)))
コード例 #7
0
ファイル: linear.py プロジェクト: lycantropos/clipping
def _subtract_segments_composite(minuend: Segment,
                                 subtrahend: Segment,
                                 context: Context
                                 ) -> Union_[Multisegment, Segment]:
    left_start, left_end, right_start, right_end = sorted([
        minuend.start, minuend.end, subtrahend.start, subtrahend.end])
    return (context.segment_cls(right_start, right_end)
            if left_start == subtrahend.start or left_start == subtrahend.end
            else (((context.segment_cls(left_start, left_end)
                    if right_start == right_end
                    else
                    context.multisegment_cls([context.segment_cls(left_start,
                                                                  left_end),
                                              context.segment_cls(right_start,
                                                                  right_end)]))
                   if (right_start == subtrahend.start
                       or right_start == subtrahend.end)
                   else context.segment_cls(left_start, left_end))
                  if left_end == subtrahend.start or left_end == subtrahend.end
                  else context.segment_cls(left_start, right_start)))
コード例 #8
0
ファイル: linear.py プロジェクト: lycantropos/clipping
def _intersect_segments_overlap(first: Segment,
                                second: Segment,
                                context: Context) -> Segment:
    _, start, end, _ = sorted([first.start, first.end, second.start,
                               second.end])
    return context.segment_cls(start, end)
コード例 #9
0
ファイル: linear.py プロジェクト: lycantropos/clipping
def _unite_segments_overlap(first: Segment,
                            second: Segment,
                            context: Context) -> Segment:
    start, _, _, end = sorted([first.start, first.end, second.start,
                               second.end])
    return context.segment_cls(start, end)
コード例 #10
0
def test_base_case(context: Context, contour: Contour) -> None:
    result = contour_self_intersects(contour)

    left_vertex, mid_vertex, right_vertex = sorted(contour.vertices)
    assert result is context.segment_contains_point(
        context.segment_cls(left_vertex, right_vertex), mid_vertex)