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)))
def validate(self) -> None: """ Checks if the contour is valid. Time complexity: ``O(vertices_count * log vertices_count)`` Memory complexity: ``O(vertices_count)`` where ``vertices_count = len(self.vertices)``. >>> from gon.base import Contour, Point >>> contour = Contour([Point(0, 0), Point(1, 0), Point(0, 1)]) >>> contour.validate() """ vertices = self._vertices vertices_count = len(vertices) if vertices_count < _vertices.MIN_COUNT: raise ValueError('Contour should have ' 'at least {expected} vertices, ' 'but found {actual}.'.format( expected=_vertices.MIN_COUNT, actual=vertices_count)) for vertex in vertices: vertex.validate() orienteer = self._context.angle_orientation if any( orienteer(vertices[index - 1], vertices[index], vertices[ (index + 1) % vertices_count]) is Orientation.COLLINEAR for index in range(vertices_count)): raise ValueError('Consecutive vertices triplets ' 'should not be on the same line.') if contour_self_intersects(self, context=self._context): raise ValueError('Contour should not be self-intersecting.')
def test_degenerate_contour(contour: Contour) -> None: with pytest.raises(ValueError): contour_self_intersects(contour)
def test_reversed_coordinates(contour: Contour) -> None: result = contour_self_intersects(contour) assert result is contour_self_intersects( reverse_contour_coordinates(contour))
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)
def test_basic(contour: Contour) -> None: result = contour_self_intersects(contour) assert isinstance(result, bool)
def is_contour_non_self_intersecting(contour: Contour) -> bool: return not contour_self_intersects(contour)