def relate_polygon(multipolygon: Multipolygon, polygon: Polygon, context: Context) -> Relation: polygon_bounding_box = context.polygon_box(polygon) all_disjoint, none_disjoint, multipolygon_max_x, events_queue = (True, True, None, None) for sub_polygon in multipolygon.polygons: sub_polygon_bounding_box = context.polygon_box(sub_polygon) if box.disjoint_with(sub_polygon_bounding_box, polygon_bounding_box): if none_disjoint: none_disjoint = False else: if all_disjoint: all_disjoint = False multipolygon_max_x = sub_polygon_bounding_box.max_x events_queue = CompoundEventsQueue(context) events_queue.register(polygon_to_oriented_segments( polygon, context), from_test=True) else: multipolygon_max_x = max(multipolygon_max_x, sub_polygon_bounding_box.max_x) events_queue.register(polygon_to_oriented_segments( sub_polygon, context), from_test=False) if all_disjoint: return Relation.DISJOINT relation = process_compound_queue( events_queue, min(multipolygon_max_x, polygon_bounding_box.max_x)) return (relation if none_disjoint else ( Relation.COMPONENT if relation is Relation.EQUAL else (Relation.OVERLAP if relation in (Relation.COVER, Relation.ENCLOSES, Relation.COMPOSITE) else relation)))
def relate_multisegment(polygon: Polygon, multisegment: Multisegment, context: Context) -> Relation: polygon_bounding_box = context.polygon_box(polygon) multisegment_bounding_box = context.segments_box(multisegment.segments) if box.disjoint_with(polygon_bounding_box, multisegment_bounding_box): return Relation.DISJOINT events_queue = CompoundEventsQueue(context) events_queue.register(to_oriented_edges_endpoints(polygon, context), from_test=False) events_queue.register(to_segments_endpoints(multisegment), from_test=True) return process_linear_compound_queue( events_queue, min(multisegment_bounding_box.max_x, polygon_bounding_box.max_x))
def relate_contour(multipolygon: Multipolygon, contour: Contour, context: Context) -> Relation: contour_bounding_box = context.contour_box(contour) disjoint, multipolygon_max_x, events_queue = True, None, None for polygon in multipolygon.polygons: polygon_bounding_box = context.polygon_box(polygon) if not box.disjoint_with(polygon_bounding_box, contour_bounding_box): if disjoint: disjoint = False multipolygon_max_x = polygon_bounding_box.max_x events_queue = CompoundEventsQueue(context) events_queue.register(contour_to_edges_endpoints(contour), from_test=True) else: multipolygon_max_x = max(multipolygon_max_x, polygon_bounding_box.max_x) events_queue.register(polygon_to_oriented_segments( polygon, context), from_test=False) return (Relation.DISJOINT if disjoint else process_linear_compound_queue( events_queue, min(contour_bounding_box.max_x, multipolygon_max_x)))
def relate_polygon(goal: Polygon, test: Polygon, context: Context) -> Relation: goal_bounding_box, test_bounding_box = (context.polygon_box(goal), context.polygon_box(test)) goal_border, goal_holes = goal.border, goal.holes test_border, test_holes = test.border, test.holes borders_relation = relate_regions(goal_border, test_border, goal_bounding_box, test_bounding_box, context) if borders_relation in (Relation.DISJOINT, Relation.TOUCH, Relation.OVERLAP): return borders_relation elif borders_relation is Relation.EQUAL: if goal_holes and test_holes: holes_relation = relate_multiregions(test_holes, goal_holes, context) if holes_relation in (Relation.DISJOINT, Relation.TOUCH, Relation.OVERLAP): return Relation.OVERLAP elif holes_relation in (Relation.COVER, Relation.ENCLOSES, Relation.COMPOSITE): return Relation.ENCLOSES elif holes_relation is Relation.EQUAL: return borders_relation else: return Relation.ENCLOSED else: return (Relation.ENCLOSES if goal_holes else (Relation.ENCLOSED if test_holes else Relation.EQUAL)) elif borders_relation in (Relation.WITHIN, Relation.ENCLOSED, Relation.COMPONENT): if goal_holes: none_touch = True subsets_holes_indices = [] for hole_index, hole in enumerate(goal_holes): hole_relation = relate_regions(test_border, hole, test_bounding_box, context.contour_box(hole), context) if hole_relation is Relation.TOUCH: if none_touch: none_touch = False elif hole_relation is Relation.OVERLAP: return hole_relation elif hole_relation is Relation.COVER: return Relation.DISJOINT elif hole_relation in (Relation.ENCLOSES, Relation.COMPOSITE, Relation.EQUAL): return Relation.TOUCH elif hole_relation is not Relation.DISJOINT: subsets_holes_indices.append(hole_index) if subsets_holes_indices: holes_relation = (relate_multiregions( test_holes, goal_holes if len(subsets_holes_indices) == len(goal_holes) else [goal_holes[index] for index in subsets_holes_indices], context) if test_holes else Relation.DISJOINT) if holes_relation is Relation.EQUAL: return (Relation.ENCLOSED if borders_relation is Relation.WITHIN else borders_relation) elif (holes_relation is Relation.COMPONENT or holes_relation is Relation.ENCLOSED): return Relation.ENCLOSED elif holes_relation is Relation.WITHIN: return borders_relation else: return Relation.OVERLAP else: return (borders_relation if none_touch else Relation.ENCLOSED) else: return (Relation.ENCLOSED if test_holes and borders_relation is Relation.COMPONENT else borders_relation) elif test_holes: none_touch = True subsets_holes_indices = [] for hole_index, hole in enumerate(test_holes): hole_relation = relate_regions(goal_border, hole, goal_bounding_box, context.contour_box(hole), context) if hole_relation is Relation.TOUCH: if none_touch: none_touch = False elif hole_relation is Relation.OVERLAP: return hole_relation elif hole_relation is Relation.COVER: return Relation.DISJOINT elif hole_relation in (Relation.ENCLOSES, Relation.COMPOSITE, Relation.EQUAL): return Relation.TOUCH elif hole_relation is not Relation.DISJOINT: subsets_holes_indices.append(hole_index) if subsets_holes_indices: holes_relation = (relate_multiregions( goal_holes, test_holes if len(subsets_holes_indices) == len(test_holes) else [test_holes[index] for index in subsets_holes_indices], context) if goal_holes else Relation.DISJOINT) if holes_relation is Relation.EQUAL: return (Relation.ENCLOSES if borders_relation is Relation.COVER else borders_relation) elif (holes_relation is Relation.COMPONENT or holes_relation is Relation.ENCLOSED): return Relation.ENCLOSES elif holes_relation is Relation.WITHIN: return borders_relation else: return Relation.OVERLAP else: return (borders_relation if none_touch else Relation.ENCLOSES) else: return (Relation.ENCLOSES if goal_holes and borders_relation is Relation.COMPOSITE else borders_relation)