def intersects_with_polygon(box: Box, polygon: Polygon, context: Context) -> bool: """ Checks if the box intersects the polygon. """ border = polygon.border polygon_box = context.contour_box(border) if not intersects_with(polygon_box, box): return False elif (is_subset_of(polygon_box, box) or any(contains_point(box, vertex) for vertex in border.vertices)): return True locations = [ point_in_region(vertex, border) for vertex in to_vertices(box, context) ] if (within_of(box, polygon_box) and all(location is Location.INTERIOR for location in locations) and all( context.segments_relation(edge, border_edge) is Relation.DISJOINT for edge in to_edges(box, context) for border_edge in context.contour_segments(border))): return not any( within_of(box, context.contour_box(hole)) and within_of_region(box, hole, context) for hole in polygon.holes) else: return (any(location is not Location.EXTERIOR for location in locations) or any( intersects_with_segment(box, edge, context) for edge in context.contour_segments(border)))
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 test_step(context: Context, segments: List[Segment]) -> None: first_segment, *rest_segments = segments result = segments_cross_or_overlap(rest_segments) next_result = segments_cross_or_overlap(segments) assert (next_result is (result or any( context.segments_relation(first_segment, segment) in (Relation.COMPONENT, Relation.COMPOSITE, Relation.CROSS, Relation.EQUAL, Relation.OVERLAP) for segment in rest_segments)))
def within_of_region(box: Box, border: Contour, context: Context) -> bool: """ Checks if the box is contained in an interior of the region. """ return (all( point_in_region(vertex, border) is Location.INTERIOR for vertex in to_vertices(box, context)) and all( context.segments_relation(edge, border_edge) is Relation.DISJOINT for edge in to_edges(box, context) for border_edge in context.contour_segments(border)))
def coupled_with_segment(box: Box, segment: Segment, context: Context) -> bool: """ Checks if the box intersects the segment at more than one point. """ segment_box = context.segment_box(segment) return (coupled_with(segment_box, box) and (is_subset_of(segment_box, box) or any( context.segments_relation(edge, segment) not in (Relation.TOUCH, Relation.DISJOINT) for edge in to_edges(box, context))))
def intersects_with_segment(box: Box, segment: Segment, context: Context) -> bool: """ Checks if the box intersects the segment. """ segment_box = context.segment_box(segment) return (intersects_with( segment_box, box) and (is_subset_of(segment_box, box) or any( context.segments_relation(edge, segment) is not Relation.DISJOINT for edge in to_edges(box, context))))
def test_step(context: Context, contour: Contour) -> None: first_vertex, *rest_vertices = contour.vertices rest_contour = Contour(rest_vertices) result = edges_intersect(rest_contour) next_result = edges_intersect(contour) first_edge, last_edge = (Segment(first_vertex, rest_vertices[0]), Segment(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( segments_pair_intersections( rest_edges[index].start, rest_edges[index].end, rest_edges[other_index].start, rest_edges[other_index].end) 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( segments_pair_intersections(edge.start, edge.end, other_edge.start, other_edge.end) in overlap_relations for edge, other_edge in combinations(rest_edges[:-1], 2))) or any( segments_pair_intersections(first_edge.start, first_edge.end, edge.start, edge.end) for edge in rest_edges[1:-1]) or any( segments_pair_intersections(last_edge.start, last_edge.end, edge.start, edge.end) for edge in rest_edges[:-2]) or len(rest_vertices) > 1 and ( context.segments_relation( first_edge.start, first_edge.end, rest_edges[0].start, rest_edges[0].end) in overlap_relations or context.segments_relation(first_edge.start, first_edge.end, last_edge.start, last_edge.end) in overlap_relations or context.segments_relation( last_edge.start, last_edge.end, rest_edges[0].start, rest_edges[0].end) in overlap_relations)))
def unite_segments(first: Segment, second: Segment, context: Context) -> Union_[Multisegment, Segment]: relation = context.segments_relation(first, second) if relation is Relation.DISJOINT: return context.multisegment_cls([first, second]) elif relation is Relation.EQUAL or relation is Relation.COMPOSITE: return first elif relation is Relation.COMPONENT: return second else: return (_unite_segments_touch if relation is Relation.TOUCH else (_unite_segments_cross if relation is Relation.CROSS else _unite_segments_overlap))(first, second, context)
def subtract_segments(minuend: Segment, subtrahend: Segment, context: Context ) -> Union_[Empty, Multisegment, Segment]: relation = context.segments_relation(minuend, subtrahend) if relation is Relation.COMPONENT or relation is Relation.EQUAL: return context.empty elif (relation is Relation.DISJOINT or relation is Relation.TOUCH or relation is Relation.CROSS): return minuend else: return (_subtract_segments_overlap(minuend, subtrahend, context) if relation is Relation.OVERLAP else _subtract_segments_composite(minuend, subtrahend, context))
def intersect_segments(first: Segment, second: Segment, context: Context) -> Union_[Empty, Multipoint, Segment]: relation = context.segments_relation(first, second) if relation is Relation.DISJOINT: return context.empty elif relation is Relation.TOUCH or relation is Relation.CROSS: return context.multipoint_cls([context.segments_intersection(first, second)]) else: return (first if relation is Relation.EQUAL or relation is Relation.COMPONENT else (second if relation is Relation.COMPOSITE else _intersect_segments_overlap(first, second, context)))
def _intersect_segment_with_multisegment(segment: Segment, multisegment: Multisegment, context: Context) -> List[Segment]: result = [] for sub_segment in multisegment.segments: relation = context.segments_relation(segment, sub_segment) if (relation is not Relation.DISJOINT and relation is not Relation.TOUCH and relation is not Relation.CROSS): result.append(segment if (relation is Relation.EQUAL or relation is Relation.COMPONENT) else (sub_segment if relation is Relation.COMPOSITE else _intersect_segments_overlap(segment, sub_segment, context))) return result
def _subtract_segment_from_multisegment(multisegment: Multisegment, segment: Segment, context: Context) -> List[Segment]: result = [] segment_cls = context.segment_cls for index, sub_segment in enumerate(multisegment.segments): relation = context.segments_relation(segment, sub_segment) if relation is Relation.EQUAL: result.extend(multisegment.segments[index + 1:]) break elif relation is Relation.COMPONENT: left_start, left_end, right_start, right_end = sorted([ sub_segment.start, sub_segment.end, segment.start, segment.end]) result.extend( [segment_cls(right_start, right_end)] if left_start == segment.start or left_start == segment.end else ((([segment_cls(left_start, left_end)] if right_start == right_end else [segment_cls(left_start, left_end), segment_cls(right_start, right_end)]) if (right_start == segment.start or right_start == segment.end) else [segment_cls(left_start, left_end)]) if left_end == segment.start or left_end == segment.end else [segment_cls(left_start, right_start)])) result.extend(multisegment.segments[index + 1:]) break elif relation is Relation.CROSS: cross_point = context.segments_intersection(sub_segment, segment) result.append(segment_cls(sub_segment.start, cross_point)) result.append(segment_cls(cross_point, sub_segment.end)) elif relation is Relation.OVERLAP: result.append(_subtract_segments_overlap(sub_segment, segment, context)) elif relation is not Relation.COMPOSITE: result.append(sub_segment) return result
def symmetric_subtract_segments(first: Segment, second: Segment, context: Context ) -> Union_[Empty, Multisegment, Segment]: relation = context.segments_relation(first, second) if relation is Relation.DISJOINT: return context.multisegment_cls([first, second]) elif relation is Relation.EQUAL: return context.empty else: return (_unite_segments_touch(first, second, context) if relation is Relation.TOUCH else (_unite_segments_cross(first, second, context) if relation is Relation.CROSS else (_symmetric_subtract_segments_overlap(first, second, context) if relation is Relation.OVERLAP else (_subtract_segments_composite(first, second, context) if relation is Relation.COMPOSITE else _subtract_segments_composite(second, first, context)))))
def test_step(context: Context, segments: List[Segment]) -> None: *rest_segments, last_segment = segments result = segments_intersections(rest_segments) next_result = segments_intersections(segments) assert (next_result.keys() == ( result.keys() | {(index, len(segments) - 1) for index, segment in enumerate(rest_segments) if context. segments_relation(segment, last_segment) is not Relation.DISJOINT})) assert result.items() <= next_result.items() assert all(segment_id < next_segment_id == len(segments) - 1 for segment_id, next_segment_id in (next_result.keys() - result.keys())) assert all( context.segments_intersection( segments[segment_id], segments[next_segment_id]) == next_result[( segment_id, next_segment_id)][0] if len(next_result[( segment_id, next_segment_id)]) == 1 else context.segments_intersection( segments[segment_id], segments[next_segment_id]) not in (Relation.DISJOINT, Relation.TOUCH, Relation.CROSS) and ( to_sorted_pair(*next_result[(segment_id, next_segment_id)]) == next_result[(segment_id, next_segment_id)]) and all( context.segment_contains_point(segments[segment_id], point) for point in next_result[(segment_id, next_segment_id)]) and all( context.segment_contains_point(segments[next_segment_id], point) for point in next_result[(segment_id, next_segment_id)]) for segment_id, next_segment_id in (next_result.keys() - result.keys())) assert all( context.segments_relation(segments[segment_id], segments[next_segment_id]) is not Relation.DISJOINT for segment_id, next_segment_id in (next_result.keys() - result.keys()))
def relate_segment(goal: Segment, test: Segment, context: Context) -> Relation: return context.segments_relation(test, goal)