Source code for clipping.planar

"""
Boolean operations on geometries in the plane.

Based on algorithm by F. Martinez et al.

Reference:
    https://doi.org/10.1016/j.advengsoft.2013.04.004
    http://www4.ujaen.es/~fmartin/bool_op.html

########
Glossary
########

**Region** --- contour with points that lie within it.

**Multiregion** --- sequence of two or more regions
such that intersection of distinct regions is a discrete points set.
"""
from typing import (Optional as _Optional,
                    Sequence as _Sequence,
                    Union as _Union)

from ground.base import (Context as _Context,
                         get_context as _get_context)
from ground.hints import (Empty as _Empty,
                          Mix as _Mix,
                          Multipoint as _Multipoint,
                          Multipolygon as _Multipolygon,
                          Multisegment as _Multisegment,
                          Polygon as _Polygon,
                          Segment as _Segment)

from .core import (holeless as _holeless,
                   holey as _holey,
                   linear as _linear,
                   mixed as _mixed,
                   operands as _operands)
from .hints import (Multiregion as _Multiregion,
                    Region as _Region)


[docs]def intersect_segments(first: _Segment, second: _Segment, *, context: _Optional[_Context] = None ) -> _Union[_Empty, _Multipoint, _Segment]: """ Returns intersection of segments. Time complexity: ``O(1)`` Memory complexity: ``O(1)`` :param first: first operand. :param second: second operand. :param context: geometric context. :returns: intersection of operands. >>> from ground.base import get_context >>> context = get_context() >>> EMPTY = context.empty >>> Multipoint = context.multipoint_cls >>> Point = context.point_cls >>> Segment = context.segment_cls >>> (intersect_segments(Segment(Point(0, 0), Point(4, 0)), ... Segment(Point(6, 0), Point(10, 0))) ... is EMPTY) True >>> (intersect_segments(Segment(Point(0, 0), Point(4, 0)), ... Segment(Point(4, 0), Point(8, 0))) ... == Multipoint([Point(4, 0)])) True >>> (intersect_segments(Segment(Point(0, 0), Point(4, 0)), ... Segment(Point(2, 0), Point(6, 0))) ... == Segment(Point(2, 0), Point(4, 0))) True """ return _linear.intersect_segments( first, second, _get_context() if context is None else context )
[docs]def subtract_segments(minuend: _Segment, subtrahend: _Segment, *, context: _Optional[_Context] = None ) -> _Union[_Empty, _Multisegment, _Segment]: """ Returns difference of segments. Time complexity: ``O(1)`` Memory complexity: ``O(1)`` :param minuend: segment to subtract from. :param subtrahend: segment to subtract. :param context: geometric context. :returns: difference of minuend with subtrahend. >>> from ground.base import get_context >>> context = get_context() >>> EMPTY = context.empty >>> Multisegment = context.multisegment_cls >>> Point = context.point_cls >>> Segment = context.segment_cls >>> (subtract_segments(Segment(Point(0, 0), Point(4, 0)), ... Segment(Point(0, 0), Point(4, 0))) ... is subtract_segments(Segment(Point(0, 0), Point(4, 0)), ... Segment(Point(0, 0), Point(6, 0))) ... is EMPTY) True >>> (subtract_segments(Segment(Point(0, 0), Point(4, 0)), ... Segment(Point(2, 0), Point(6, 0))) ... == Segment(Point(0, 0), Point(2, 0))) True >>> (subtract_segments(Segment(Point(0, 0), Point(4, 0)), ... Segment(Point(6, 0), Point(10, 0))) ... == subtract_segments(Segment(Point(0, 0), Point(4, 0)), ... Segment(Point(4, 0), Point(8, 0))) ... == Segment(Point(0, 0), Point(4, 0))) True >>> (subtract_segments(Segment(Point(0, 0), Point(4, 0)), ... Segment(Point(1, 0), Point(3, 0))) ... == Multisegment([Segment(Point(0, 0), Point(1, 0)), ... Segment(Point(3, 0), Point(4, 0))])) True """ return _linear.subtract_segments( minuend, subtrahend, _get_context() if context is None else context )
[docs]def symmetric_subtract_segments(first: _Segment, second: _Segment, *, context: _Optional[_Context] = None ) -> _Union[_Empty, _Multisegment, _Segment]: """ Returns symmetric difference of segments. Time complexity: ``O(1)`` Memory complexity: ``O(1)`` :param first: first operand. :param second: second operand. :param context: geometric context. :returns: symmetric difference of operands. >>> from ground.base import get_context >>> context = get_context() >>> EMPTY = context.empty >>> Multisegment = context.multisegment_cls >>> Point = context.point_cls >>> Segment = context.segment_cls >>> (symmetric_subtract_segments(Segment(Point(0, 0), Point(4, 0)), ... Segment(Point(0, 0), Point(4, 0))) ... is EMPTY) True >>> (symmetric_subtract_segments(Segment(Point(0, 0), Point(4, 0)), ... Segment(Point(4, 0), Point(8, 0))) ... == Segment(Point(0, 0), Point(8, 0))) True >>> (symmetric_subtract_segments(Segment(Point(0, 0), Point(4, 0)), ... Segment(Point(1, 0), Point(3, 0))) ... == Multisegment([Segment(Point(0, 0), Point(1, 0)), ... Segment(Point(3, 0), Point(4, 0))])) True >>> (symmetric_subtract_segments(Segment(Point(0, 0), Point(4, 0)), ... Segment(Point(2, 0), Point(6, 0))) ... == Multisegment([Segment(Point(0, 0), Point(2, 0)), ... Segment(Point(4, 0), Point(6, 0))])) True >>> (symmetric_subtract_segments(Segment(Point(0, 0), Point(4, 0)), ... Segment(Point(6, 0), Point(10, 0))) ... == Multisegment([Segment(Point(0, 0), Point(4, 0)), ... Segment(Point(6, 0), Point(10, 0))])) True """ return _linear.symmetric_subtract_segments( first, second, _get_context() if context is None else context )
[docs]def unite_segments(first: _Segment, second: _Segment, *, context: _Optional[_Context] = None ) -> _Union[_Multisegment, _Segment]: """ Returns union of segments. Time complexity: ``O(1)`` Memory complexity: ``O(1)`` :param first: first operand. :param second: second operand. :param context: geometric context. :returns: union of operands. >>> from ground.base import get_context >>> context = get_context() >>> EMPTY = context.empty >>> Multisegment = context.multisegment_cls >>> Point = context.point_cls >>> Segment = context.segment_cls >>> (unite_segments(Segment(Point(0, 0), Point(4, 0)), ... Segment(Point(0, 0), Point(4, 0))) ... == unite_segments(Segment(Point(0, 0), Point(4, 0)), ... Segment(Point(1, 0), Point(3, 0))) ... == Segment(Point(0, 0), Point(4, 0))) True >>> (unite_segments(Segment(Point(0, 0), Point(4, 0)), ... Segment(Point(4, 0), Point(8, 0))) ... == Segment(Point(0, 0), Point(8, 0))) True >>> (unite_segments(Segment(Point(0, 0), Point(4, 0)), ... Segment(Point(2, 0), Point(6, 0))) ... == Segment(Point(0, 0), Point(6, 0))) True >>> (unite_segments(Segment(Point(0, 0), Point(4, 0)), ... Segment(Point(6, 0), Point(10, 0))) ... == Multisegment([Segment(Point(0, 0), Point(4, 0)), ... Segment(Point(6, 0), Point(10, 0))])) True """ return _linear.unite_segments( first, second, _get_context() if context is None else context )
[docs]def complete_intersect_segment_with_multisegment( segment: _Segment, multisegment: _Multisegment, *, context: _Optional[_Context] = None ) -> _Union[_Empty, _Mix, _Multipoint, _Multisegment, _Segment]: """ Returns intersection of segment with multisegment considering cases with geometries touching each other in points. Time complexity: ``O(segments_count * log segments_count)`` Memory complexity: ``O(segments_count)`` where ``segments_count = segments_count + intersections_count``, ``segments_count = len(subtrahend.segments) + 1``, ``intersections_count`` --- number of intersections between segments. :param segment: first operand. :param multisegment: second operand. :param context: geometric context. :returns: intersection of operands. >>> from ground.base import get_context >>> context = get_context() >>> EMPTY = context.empty >>> Mix = context.mix_cls >>> Multipoint = context.multipoint_cls >>> Multisegment = context.multisegment_cls >>> Point = context.point_cls >>> Segment = context.segment_cls >>> (complete_intersect_segment_with_multisegment( ... Segment(Point(0, 0), Point(4, 0)), ... Multisegment([Segment(Point(6, 0), Point(10, 0)), ... Segment(Point(6, 0), Point(6, 4))])) ... is EMPTY) True >>> (complete_intersect_segment_with_multisegment( ... Segment(Point(0, 0), Point(4, 0)), ... Multisegment([Segment(Point(4, 0), Point(8, 0)), ... Segment(Point(4, 0), Point(4, 4))])) ... == Multipoint([Point(4, 0)])) True >>> (complete_intersect_segment_with_multisegment( ... Segment(Point(0, 0), Point(4, 0)), ... Multisegment([Segment(Point(0, 0), Point(4, 0)), ... Segment(Point(0, 0), Point(0, 4))])) ... == Segment(Point(0, 0), Point(4, 0))) True >>> (complete_intersect_segment_with_multisegment( ... Segment(Point(0, 0), Point(4, 0)), ... Multisegment([Segment(Point(0, 0), Point(1, 0)), ... Segment(Point(3, 0), Point(4, 0))])) ... == Multisegment([Segment(Point(0, 0), Point(1, 0)), ... Segment(Point(3, 0), Point(4, 0))])) True >>> (complete_intersect_segment_with_multisegment( ... Segment(Point(0, 0), Point(4, 0)), ... Multisegment([Segment(Point(0, 0), Point(1, 0)), ... Segment(Point(2, 0), Point(2, 1)), ... Segment(Point(3, 0), Point(4, 0))])) ... == Mix(Multipoint([Point(2, 0)]), ... Multisegment([Segment(Point(0, 0), Point(1, 0)), ... Segment(Point(3, 0), Point(4, 0))]), EMPTY)) True """ return _linear.CompleteIntersection( _operands.SegmentOperand(segment), _operands.MultisegmentOperand(multisegment), _get_context() if context is None else context ).compute()
[docs]def intersect_segment_with_multisegment( segment: _Segment, multisegment: _Multisegment, *, context: _Optional[_Context] = None ) -> _Union[_Empty, _Multisegment, _Segment]: """ Returns intersection of segments. Time complexity: ``O(len(multisegment.segments))`` Memory complexity: ``O(len(multisegment.segments))`` :param segment: first operand. :param multisegment: second operand. :param context: geometric context. :returns: intersection of operands. >>> from ground.base import get_context >>> context = get_context() >>> EMPTY = context.empty >>> Multisegment = context.multisegment_cls >>> Point = context.point_cls >>> Segment = context.segment_cls >>> (intersect_segment_with_multisegment( ... Segment(Point(0, 0), Point(4, 0)), ... Multisegment([Segment(Point(6, 0), Point(10, 0)), ... Segment(Point(6, 0), Point(6, 4))])) ... is intersect_segment_with_multisegment( ... Segment(Point(0, 0), Point(4, 0)), ... Multisegment([Segment(Point(4, 0), Point(8, 0)), ... Segment(Point(4, 0), Point(4, 4))])) ... is EMPTY) True >>> (intersect_segment_with_multisegment( ... Segment(Point(0, 0), Point(4, 0)), ... Multisegment([Segment(Point(0, 0), Point(4, 0)), ... Segment(Point(0, 0), Point(0, 4))])) ... == Segment(Point(0, 0), Point(4, 0))) True >>> (intersect_segment_with_multisegment( ... Segment(Point(0, 0), Point(4, 0)), ... Multisegment([Segment(Point(0, 0), Point(1, 0)), ... Segment(Point(3, 0), Point(4, 0))])) ... == Multisegment([Segment(Point(0, 0), Point(1, 0)), ... Segment(Point(3, 0), Point(4, 0))])) True >>> (intersect_segment_with_multisegment( ... Segment(Point(0, 0), Point(4, 0)), ... Multisegment([Segment(Point(0, 0), Point(1, 0)), ... Segment(Point(2, 0), Point(2, 1)), ... Segment(Point(3, 0), Point(4, 0))])) ... == Multisegment([Segment(Point(0, 0), Point(1, 0)), ... Segment(Point(3, 0), Point(4, 0))])) True """ return _linear.intersect_segment_with_multisegment( segment, multisegment, _get_context() if context is None else context )
[docs]def subtract_multisegment_from_segment( minuend: _Segment, subtrahend: _Multisegment, *, context: _Optional[_Context] = None ) -> _Union[_Empty, _Multisegment, _Segment]: """ Returns difference of segment with multisegment. Time complexity: ``O(segments_count * log segments_count)`` Memory complexity: ``O(segments_count)`` where ``segments_count = segments_count + intersections_count``, ``segments_count = len(subtrahend.segments) + 1``, ``intersections_count`` --- number of intersections between segments. :param minuend: segment to subtract from. :param subtrahend: multisegment to subtract. :param context: geometric context. :returns: difference of minuend with subtrahend. >>> from ground.base import get_context >>> context = get_context() >>> EMPTY = context.empty >>> Multisegment = context.multisegment_cls >>> Point = context.point_cls >>> Segment = context.segment_cls >>> (subtract_multisegment_from_segment( ... Segment(Point(0, 0), Point(4, 0)), ... Multisegment([Segment(Point(0, 0), Point(4, 0)), ... Segment(Point(0, 1), Point(0, 3))])) ... is subtract_multisegment_from_segment( ... Segment(Point(0, 0), Point(4, 0)), ... Multisegment([Segment(Point(0, 0), Point(6, 0)), ... Segment(Point(0, 1), Point(0, 3))])) ... is EMPTY) True >>> (subtract_multisegment_from_segment( ... Segment(Point(0, 0), Point(4, 0)), ... Multisegment([Segment(Point(2, 0), Point(4, 0)), ... Segment(Point(0, 1), Point(0, 3))])) ... == Segment(Point(0, 0), Point(2, 0))) True >>> (subtract_multisegment_from_segment( ... Segment(Point(0, 0), Point(4, 0)), ... Multisegment([Segment(Point(3, 0), Point(4, 0)), ... Segment(Point(0, 0), Point(1, 0))])) ... == Segment(Point(1, 0), Point(3, 0))) True >>> (subtract_multisegment_from_segment( ... Segment(Point(0, 0), Point(4, 0)), ... Multisegment([Segment(Point(6, 0), Point(10, 0)), ... Segment(Point(0, 1), Point(0, 3))])) ... == subtract_multisegment_from_segment( ... Segment(Point(0, 0), Point(4, 0)), ... Multisegment([Segment(Point(4, 0), Point(8, 0)), ... Segment(Point(0, 1), Point(0, 3))])) ... == Segment(Point(0, 0), Point(4, 0))) True >>> (subtract_multisegment_from_segment( ... Segment(Point(0, 0), Point(4, 0)), ... Multisegment([Segment(Point(1, 0), Point(3, 0)), ... Segment(Point(0, 1), Point(0, 3))])) ... == Multisegment([Segment(Point(0, 0), Point(1, 0)), ... Segment(Point(3, 0), Point(4, 0))])) True """ return (_linear.Difference(_operands.SegmentOperand(minuend), _operands.MultisegmentOperand(subtrahend), _get_context() if context is None else context) .compute())
[docs]def subtract_segment_from_multisegment( minuend: _Multisegment, subtrahend: _Segment, *, context: _Optional[_Context] = None ) -> _Union[_Empty, _Multisegment, _Segment]: """ Returns difference of segment with multisegment. Time complexity: ``O(len(subtrahend.segments))`` Memory complexity: ``O(len(subtrahend.segments))`` :param minuend: multisegment to subtract from. :param subtrahend: segment to subtract. :param context: geometric context. :returns: difference of minuend with subtrahend. >>> from ground.base import get_context >>> context = get_context() >>> EMPTY = context.empty >>> Multisegment = context.multisegment_cls >>> Point = context.point_cls >>> Segment = context.segment_cls >>> (subtract_segment_from_multisegment( ... Multisegment([Segment(Point(0, 0), Point(1, 0)), ... Segment(Point(3, 0), Point(4, 0))]), ... Segment(Point(0, 0), Point(4, 0))) ... is subtract_segment_from_multisegment( ... Multisegment([Segment(Point(0, 0), Point(1, 0)), ... Segment(Point(3, 0), Point(4, 0))]), ... Segment(Point(0, 0), Point(6, 0))) ... is EMPTY) True >>> (subtract_segment_from_multisegment( ... Multisegment([Segment(Point(0, 0), Point(2, 0)), ... Segment(Point(0, 1), Point(0, 3))]), ... Segment(Point(0, 1), Point(0, 3))) ... == subtract_segment_from_multisegment( ... Multisegment([Segment(Point(0, 0), Point(2, 0)), ... Segment(Point(3, 0), Point(4, 0))]), ... Segment(Point(2, 0), Point(4, 0))) ... == Segment(Point(0, 0), Point(2, 0))) True >>> (subtract_segment_from_multisegment( ... Multisegment([Segment(Point(0, 0), Point(1, 0)), ... Segment(Point(3, 0), Point(4, 0))]), ... Segment(Point(1, 0), Point(3, 0))) ... == Multisegment([Segment(Point(0, 0), Point(1, 0)), ... Segment(Point(3, 0), Point(4, 0))])) True >>> (subtract_segment_from_multisegment( ... Multisegment([Segment(Point(0, 0), Point(4, 0)), ... Segment(Point(0, 1), Point(0, 3))]), ... Segment(Point(1, 0), Point(3, 0))) ... == Multisegment([Segment(Point(0, 0), Point(1, 0)), ... Segment(Point(3, 0), Point(4, 0)), ... Segment(Point(0, 1), Point(0, 3))])) True """ return _linear.subtract_segment_from_multisegment( minuend, subtrahend, _get_context() if context is None else context )
[docs]def symmetric_subtract_multisegment_from_segment( first: _Segment, second: _Multisegment, *, context: _Optional[_Context] = None ) -> _Union[_Empty, _Multisegment, _Segment]: """ Returns symmetric difference of segment and multisegment. Time complexity: ``O(segments_count * log segments_count)`` Memory complexity: ``O(segments_count)`` where ``segments_count = segments_count + intersections_count``, ``segments_count = len(second.segments) + 1``, ``intersections_count`` --- number of intersections between segments. :param first: first operand. :param second: second operand. :param context: geometric context. :returns: symmetric difference of operands. >>> from ground.base import get_context >>> context = get_context() >>> EMPTY = context.empty >>> Multisegment = context.multisegment_cls >>> Point = context.point_cls >>> Segment = context.segment_cls >>> (symmetric_subtract_multisegment_from_segment( ... Segment(Point(0, 0), Point(4, 0)), ... Multisegment([Segment(Point(0, 0), Point(2, 0)), ... Segment(Point(2, 0), Point(4, 0))])) ... is EMPTY) True >>> (symmetric_subtract_multisegment_from_segment( ... Segment(Point(0, 0), Point(4, 0)), ... Multisegment([Segment(Point(0, 0), Point(4, 0)), ... Segment(Point(0, 1), Point(0, 3))])) ... == Segment(Point(0, 1), Point(0, 3))) True >>> (symmetric_subtract_multisegment_from_segment( ... Segment(Point(0, 0), Point(4, 0)), ... Multisegment([Segment(Point(0, 0), Point(1, 0)), ... Segment(Point(3, 0), Point(4, 0))])) ... == Segment(Point(1, 0), Point(3, 0))) True >>> (symmetric_subtract_multisegment_from_segment( ... Segment(Point(0, 0), Point(4, 0)), ... Multisegment([Segment(Point(4, 0), Point(8, 0)), ... Segment(Point(0, 1), Point(0, 3))])) ... == Multisegment([Segment(Point(0, 0), Point(4, 0)), ... Segment(Point(0, 1), Point(0, 3)), ... Segment(Point(4, 0), Point(8, 0))])) True >>> (symmetric_subtract_multisegment_from_segment( ... Segment(Point(0, 0), Point(4, 0)), ... Multisegment([Segment(Point(1, 0), Point(3, 0)), ... Segment(Point(0, 1), Point(0, 3))])) ... == Multisegment([Segment(Point(0, 0), Point(1, 0)), ... Segment(Point(0, 1), Point(0, 3)), ... Segment(Point(3, 0), Point(4, 0))])) True """ return _linear.SymmetricDifference( _operands.SegmentOperand(first), _operands.MultisegmentOperand(second), _get_context() if context is None else context ).compute()
[docs]def unite_segment_with_multisegment(first: _Segment, second: _Multisegment, *, context: _Optional[_Context] = None ) -> _Union[_Multisegment, _Segment]: """ Returns symmetric difference of segment and multisegment. Time complexity: ``O(len(second.segments))`` Memory complexity: ``O(len(second.segments))`` :param first: first operand. :param second: second operand. :param context: geometric context. :returns: symmetric difference of operands. >>> from ground.base import get_context >>> context = get_context() >>> EMPTY = context.empty >>> Multisegment = context.multisegment_cls >>> Point = context.point_cls >>> Segment = context.segment_cls >>> (unite_segment_with_multisegment( ... Segment(Point(0, 0), Point(4, 0)), ... Multisegment([Segment(Point(0, 0), Point(2, 0)), ... Segment(Point(2, 0), Point(4, 0))])) ... == unite_segment_with_multisegment( ... Segment(Point(0, 0), Point(4, 0)), ... Multisegment([Segment(Point(0, 0), Point(1, 0)), ... Segment(Point(3, 0), Point(4, 0))])) ... == Segment(Point(0, 0), Point(4, 0))) True >>> (unite_segment_with_multisegment( ... Segment(Point(0, 0), Point(4, 0)), ... Multisegment([Segment(Point(0, 0), Point(4, 0)), ... Segment(Point(0, 1), Point(0, 3))])) ... == Multisegment([Segment(Point(0, 1), Point(0, 3)), ... Segment(Point(0, 0), Point(4, 0))])) True >>> (unite_segment_with_multisegment( ... Segment(Point(0, 0), Point(4, 0)), ... Multisegment([Segment(Point(4, 0), Point(8, 0)), ... Segment(Point(0, 1), Point(0, 3))])) ... == Multisegment([Segment(Point(4, 0), Point(8, 0)), ... Segment(Point(0, 1), Point(0, 3)), ... Segment(Point(0, 0), Point(4, 0))])) True >>> (unite_segment_with_multisegment( ... Segment(Point(1, 0), Point(3, 0)), ... Multisegment([Segment(Point(0, 0), Point(4, 0)), ... Segment(Point(0, 1), Point(0, 3))])) ... == Multisegment([Segment(Point(0, 0), Point(1, 0)), ... Segment(Point(3, 0), Point(4, 0)), ... Segment(Point(0, 1), Point(0, 3)), ... Segment(Point(1, 0), Point(3, 0))])) True """ return _linear.unite_segment_with_multisegment( first, second, _get_context() if context is None else context )
[docs]def complete_intersect_segment_with_polygon( segment: _Segment, polygon: _Polygon, *, context: _Optional[_Context] = None ) -> _Union[_Empty, _Mix, _Multipoint, _Multisegment, _Segment]: """ Returns intersection of segment with polygon considering cases with geometries touching each other in points. Time complexity: ``O(segments_count * log segments_count)`` Memory complexity: ``O(segments_count)`` where ``segments_count = start_segments_count + intersections_count``, ``start_segments_count = polygon_edges_count + 1``, ``polygon_edges_count = len(polygon.border.vertices)\ + sum(len(hole.vertices) for hole in polygon.holes)``, ``intersections_count`` --- number of intersections between segment and polygon edges. :param segment: first operand. :param polygon: second operand. :param context: geometric context. :returns: intersection of operands. >>> from ground.base import get_context >>> context = get_context() >>> EMPTY = context.empty >>> Contour = context.contour_cls >>> Mix = context.mix_cls >>> Multipoint = context.multipoint_cls >>> Multisegment = context.multisegment_cls >>> Point = context.point_cls >>> Polygon = context.polygon_cls >>> Segment = context.segment_cls >>> square = Contour([Point(0, 0), Point(4, 0), Point(4, 4), ... Point(0, 4)]) >>> inner_square = Contour([Point(1, 1), Point(3, 1), Point(3, 3), ... Point(1, 3)]) >>> clockwise_inner_square = Contour([Point(1, 1), Point(1, 3), ... Point(3, 3), Point(3, 1)]) >>> (complete_intersect_segment_with_polygon( ... Segment(Point(0, 0), Point(1, 0)), Polygon(inner_square, [])) ... is EMPTY) True >>> (complete_intersect_segment_with_polygon( ... Segment(Point(0, 0), Point(1, 1)), Polygon(inner_square, [])) ... == Multipoint([Point(1, 1)])) True >>> (complete_intersect_segment_with_polygon( ... Segment(Point(0, 0), Point(1, 1)), Polygon(square, [])) ... == Segment(Point(0, 0), Point(1, 1))) True >>> (complete_intersect_segment_with_polygon( ... Segment(Point(0, 0), Point(4, 4)), ... Polygon(square, [clockwise_inner_square])) ... == Multisegment([Segment(Point(0, 0), Point(1, 1)), ... Segment(Point(3, 3), Point(4, 4))])) True >>> (complete_intersect_segment_with_polygon( ... Segment(Point(1, 1), Point(4, 4)), ... Polygon(square, [clockwise_inner_square])) ... == Mix(Multipoint([Point(1, 1)]), Segment(Point(3, 3), Point(4, 4)), ... EMPTY)) True """ return _mixed.CompleteIntersection( _operands.SegmentOperand(segment), _operands.PolygonOperand(polygon), _get_context() if context is None else context ).compute()
[docs]def intersect_segment_with_polygon(segment: _Segment, polygon: _Polygon, *, context: _Optional[_Context] = None ) -> _Union[_Empty, _Multisegment, _Segment]: """ Returns intersection of segment with polygon. Time complexity: ``O(segments_count * log segments_count)`` Memory complexity: ``O(segments_count)`` where ``segments_count = start_segments_count + intersections_count``, ``start_segments_count = polygon_edges_count + 1``, ``polygon_edges_count = len(polygon.border.vertices)\ + sum(len(hole.vertices) for hole in polygon.holes)``, ``intersections_count`` --- number of intersections between segment and polygon edges. :param segment: first operand. :param polygon: second operand. :param context: geometric context. :returns: intersection of operands. >>> from ground.base import get_context >>> context = get_context() >>> EMPTY = context.empty >>> Contour = context.contour_cls >>> Multisegment = context.multisegment_cls >>> Point = context.point_cls >>> Polygon = context.polygon_cls >>> Segment = context.segment_cls >>> square = Contour([Point(0, 0), Point(4, 0), Point(4, 4), ... Point(0, 4)]) >>> inner_square = Contour([Point(1, 1), Point(3, 1), Point(3, 3), ... Point(1, 3)]) >>> clockwise_inner_square = Contour([Point(1, 1), Point(1, 3), ... Point(3, 3), Point(3, 1)]) >>> (intersect_segment_with_polygon(Segment(Point(0, 0), Point(1, 0)), ... Polygon(inner_square, [])) ... is intersect_segment_with_polygon(Segment(Point(0, 0), Point(1, 1)), ... Polygon(inner_square, [])) ... is EMPTY) True >>> (intersect_segment_with_polygon(Segment(Point(0, 0), Point(1, 1)), ... Polygon(square, [])) ... == Segment(Point(0, 0), Point(1, 1))) True >>> (intersect_segment_with_polygon(Segment(Point(1, 1), Point(4, 4)), ... Polygon(square, ... [clockwise_inner_square])) ... == Segment(Point(3, 3), Point(4, 4))) True >>> (intersect_segment_with_polygon(Segment(Point(0, 0), Point(4, 4)), ... Polygon(square, ... [clockwise_inner_square])) ... == Multisegment([Segment(Point(0, 0), Point(1, 1)), ... Segment(Point(3, 3), Point(4, 4))])) True """ return (_mixed.Intersection(_operands.SegmentOperand(segment), _operands.PolygonOperand(polygon), _get_context() if context is None else context) .compute())
[docs]def subtract_polygon_from_segment(minuend: _Segment, subtrahend: _Polygon, *, context: _Optional[_Context] = None ) -> _Union[_Empty, _Multisegment, _Segment]: """ Returns difference of segment with polygon. Time complexity: ``O(segments_count * log segments_count)`` Memory complexity: ``O(segments_count)`` where ``segments_count = start_segments_count + intersections_count``, ``start_segments_count = subtrahend_edges_count + 1``, ``subtrahend_edges_count = sum(len(polygon.border.vertices)\ + sum(len(hole.vertices) for hole in polygon.holes)\ for polygon in subtrahend.polygons)``, ``intersections_count`` --- number of intersections between segment and polygon edges. :param minuend: segment to subtract from. :param subtrahend: polygon to subtract. :param context: geometric context. :returns: difference of minuend with subtrahend. >>> from ground.base import get_context >>> context = get_context() >>> EMPTY = context.empty >>> Contour = context.contour_cls >>> Multisegment = context.multisegment_cls >>> Point = context.point_cls >>> Polygon = context.polygon_cls >>> Segment = context.segment_cls >>> square = Contour([Point(0, 0), Point(4, 0), Point(4, 4), Point(0, 4)]) >>> inner_square = Contour([Point(1, 1), Point(3, 1), Point(3, 3), ... Point(1, 3)]) >>> clockwise_inner_square = Contour([Point(1, 1), Point(1, 3), ... Point(3, 3), Point(3, 1)]) >>> (subtract_polygon_from_segment(Segment(Point(0, 0), Point(1, 1)), ... Polygon(square, [])) ... is EMPTY) True >>> (subtract_polygon_from_segment(Segment(Point(0, 0), Point(1, 0)), ... Polygon(inner_square, [])) ... == Segment(Point(0, 0), Point(1, 0))) True >>> (subtract_polygon_from_segment(Segment(Point(0, 0), Point(1, 1)), ... Polygon(inner_square, [])) ... == Segment(Point(0, 0), Point(1, 1))) True >>> (subtract_polygon_from_segment(Segment(Point(1, 1), Point(4, 4)), ... Polygon(square, ... [clockwise_inner_square])) ... == subtract_polygon_from_segment(Segment(Point(0, 0), Point(4, 4)), ... Polygon(square, ... [clockwise_inner_square])) ... == Segment(Point(1, 1), Point(3, 3))) True >>> (subtract_polygon_from_segment(Segment(Point(0, 0), Point(4, 4)), ... Polygon(inner_square, [])) ... == Multisegment([Segment(Point(0, 0), Point(1, 1)), ... Segment(Point(3, 3), Point(4, 4))])) True """ return (_mixed.Difference(_operands.SegmentOperand(minuend), _operands.PolygonOperand(subtrahend), _get_context() if context is None else context) .compute())
[docs]def symmetric_subtract_polygon_from_segment(segment: _Segment, polygon: _Polygon, *, context: _Optional[_Context] = None ) -> _Union[_Mix, _Polygon]: """ Returns symmetric difference of segment with polygon. Time complexity: ``O(segments_count * log segments_count)`` Memory complexity: ``O(segments_count)`` where ``segments_count = start_segments_count + intersections_count``, ``start_segments_count = polygon_edges_count + 1``, ``polygon_edges_count = len(polygon.border.vertices)\ + sum(len(hole.vertices) for hole in polygon.holes)``, ``intersections_count`` --- number of intersections between segment and polygon edges. :param segment: first operand. :param polygon: second operand. :param context: geometric context. :returns: symmetric difference of operands. >>> from ground.base import get_context >>> context = get_context() >>> EMPTY = context.empty >>> Contour = context.contour_cls >>> Mix = context.mix_cls >>> Multisegment = context.multisegment_cls >>> Point = context.point_cls >>> Polygon = context.polygon_cls >>> Segment = context.segment_cls >>> square = Contour([Point(0, 0), Point(4, 0), Point(4, 4), ... Point(0, 4)]) >>> inner_square = Contour([Point(1, 1), Point(3, 1), Point(3, 3), ... Point(1, 3)]) >>> clockwise_inner_square = Contour([Point(1, 1), Point(1, 3), ... Point(3, 3), Point(3, 1)]) >>> (symmetric_subtract_polygon_from_segment( ... Segment(Point(0, 0), Point(1, 1)), Polygon(square, [])) ... == Polygon(square, [])) True >>> (symmetric_subtract_polygon_from_segment( ... Segment(Point(0, 0), Point(1, 1)), Polygon(inner_square, [])) ... == Mix(EMPTY, Segment(Point(0, 0), Point(1, 1)), ... Polygon(inner_square, []))) True >>> (symmetric_subtract_polygon_from_segment( ... Segment(Point(1, 1), Point(8, 8)), ... Polygon(square, [clockwise_inner_square])) ... == Mix(EMPTY, Multisegment([Segment(Point(1, 1), Point(3, 3)), ... Segment(Point(4, 4), Point(8, 8))]), ... Polygon(square, [clockwise_inner_square]))) True """ return _mixed.SymmetricDifference( _operands.SegmentOperand(segment), _operands.PolygonOperand(polygon), _get_context() if context is None else context ).compute()
[docs]def unite_segment_with_polygon(segment: _Segment, polygon: _Polygon, *, context: _Optional[_Context] = None ) -> _Union[_Mix, _Polygon]: """ Returns union of segment with polygon. Time complexity: ``O(segments_count * log segments_count)`` Memory complexity: ``O(segments_count)`` where ``segments_count = start_segments_count + intersections_count``, ``start_segments_count = polygon_edges_count + 1``, ``polygon_edges_count = len(polygon.border.vertices)\ + sum(len(hole.vertices) for hole in polygon.holes)``, ``intersections_count`` --- number of intersections between segment and polygon edges. :param segment: first operand. :param polygon: second operand. :param context: geometric context. :returns: union of operands. >>> from ground.base import get_context >>> context = get_context() >>> EMPTY = context.empty >>> Contour = context.contour_cls >>> Mix = context.mix_cls >>> Multisegment = context.multisegment_cls >>> Point = context.point_cls >>> Polygon = context.polygon_cls >>> Segment = context.segment_cls >>> square = Contour([Point(0, 0), Point(4, 0), Point(4, 4), ... Point(0, 4)]) >>> inner_square = Contour([Point(1, 1), Point(3, 1), Point(3, 3), ... Point(1, 3)]) >>> clockwise_inner_square = Contour([Point(1, 1), Point(1, 3), ... Point(3, 3), Point(3, 1)]) >>> (unite_segment_with_polygon(Segment(Point(0, 0), Point(1, 1)), ... Polygon(square, [])) ... == Polygon(square, [])) True >>> (unite_segment_with_polygon(Segment(Point(0, 0), Point(1, 1)), ... Polygon(inner_square, [])) ... == Mix(EMPTY, Segment(Point(0, 0), Point(1, 1)), ... Polygon(inner_square, []))) True >>> (unite_segment_with_polygon(Segment(Point(1, 1), Point(8, 8)), ... Polygon(square, [clockwise_inner_square])) ... == Mix(EMPTY, Multisegment([Segment(Point(1, 1), Point(3, 3)), ... Segment(Point(4, 4), Point(8, 8))]), ... Polygon(square, [clockwise_inner_square]))) True """ return (_mixed.Union(_operands.SegmentOperand(segment), _operands.PolygonOperand(polygon), _get_context() if context is None else context) .compute())
[docs]def complete_intersect_segment_with_multipolygon( segment: _Segment, multipolygon: _Multipolygon, *, context: _Optional[_Context] = None ) -> _Union[_Empty, _Mix, _Multipoint, _Multisegment, _Segment]: """ Returns intersection of segment with multipolygon considering cases with geometries touching each other in points. Time complexity: ``O(segments_count * log segments_count)`` Memory complexity: ``O(segments_count)`` where ``segments_count = start_segments_count + intersections_count``, ``start_segments_count = multipolygon_edges_count + 1``, ``multipolygon_edges_count = sum(len(polygon.border.vertices)\ + sum(len(hole.vertices) for hole in polygon.holes)\ for polygon in multipolygon.polygons)``, ``intersections_count`` --- number of intersections between segment and multipolygon edges. :param segment: first operand. :param multipolygon: second operand. :param context: geometric context. :returns: intersection of operands. >>> from ground.base import get_context >>> context = get_context() >>> EMPTY = context.empty >>> Mix = context.mix_cls >>> Contour = context.contour_cls >>> Multipoint = context.multipoint_cls >>> Multipolygon = context.multipolygon_cls >>> Multisegment = context.multisegment_cls >>> Point = context.point_cls >>> Polygon = context.polygon_cls >>> Segment = context.segment_cls >>> first_square = Contour([Point(0, 0), Point(4, 0), Point(4, 4), ... Point(0, 4)]) >>> second_square = Contour([Point(4, 0), Point(8, 0), Point(8, 4), ... Point(4, 4)]) >>> third_square = Contour([Point(4, 4), Point(8, 4), Point(8, 8), ... Point(4, 8)]) >>> first_inner_square = Contour([Point(1, 1), Point(3, 1), Point(3, 3), ... Point(1, 3)]) >>> clockwise_first_inner_square = Contour([Point(1, 1), Point(1, 3), ... Point(3, 3), Point(3, 1)]) >>> (complete_intersect_segment_with_multipolygon( ... Segment(Point(0, 0), Point(2, 0)), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_square, [])])) ... is EMPTY) True >>> (complete_intersect_segment_with_multipolygon( ... Segment(Point(0, 0), Point(4, 0)), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_square, [])])) ... == Multipoint([Point(4, 0)])) True >>> (complete_intersect_segment_with_multipolygon( ... Segment(Point(0, 0), Point(2, 2)), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_square, [])])) ... == Segment(Point(1, 1), Point(2, 2))) True >>> (complete_intersect_segment_with_multipolygon( ... Segment(Point(0, 0), Point(4, 4)), ... Multipolygon([Polygon(first_square, ... [clockwise_first_inner_square]), ... Polygon(third_square, [])])) ... == Multisegment([Segment(Point(0, 0), Point(1, 1)), ... Segment(Point(3, 3), Point(4, 4))])) True >>> (complete_intersect_segment_with_multipolygon( ... Segment(Point(1, 1), Point(8, 8)), ... Multipolygon([Polygon(first_square, ... [clockwise_first_inner_square]), ... Polygon(third_square, [])])) ... == Mix(Multipoint([Point(1, 1)]), ... Multisegment([Segment(Point(3, 3), Point(4, 4)), ... Segment(Point(4, 4), Point(8, 8))]), EMPTY)) True """ return _mixed.CompleteIntersection( _operands.SegmentOperand(segment), _operands.MultipolygonOperand(multipolygon), _get_context() if context is None else context ).compute()
[docs]def intersect_segment_with_multipolygon(segment: _Segment, multipolygon: _Multipolygon, *, context: _Optional[_Context] = None ) -> _Union[_Empty, _Multisegment, _Segment]: """ Returns intersection of segment with multipolygon. Time complexity: ``O(segments_count * log segments_count)`` Memory complexity: ``O(segments_count)`` where ``segments_count = start_segments_count + intersections_count``, ``start_segments_count = multipolygon_edges_count + 1``, ``multipolygon_edges_count = sum(len(polygon.border.vertices)\ + sum(len(hole.vertices) for hole in polygon.holes)\ for polygon in multipolygon.polygons)``, ``intersections_count`` --- number of intersections between segment and multipolygon edges. :param segment: first operand. :param multipolygon: second operand. :param context: geometric context. :returns: intersection of operands. >>> from ground.base import get_context >>> context = get_context() >>> EMPTY = context.empty >>> Contour = context.contour_cls >>> Multipolygon = context.multipolygon_cls >>> Multisegment = context.multisegment_cls >>> Point = context.point_cls >>> Polygon = context.polygon_cls >>> Segment = context.segment_cls >>> first_square = Contour([Point(0, 0), Point(4, 0), Point(4, 4), ... Point(0, 4)]) >>> second_square = Contour([Point(4, 0), Point(8, 0), Point(8, 4), ... Point(4, 4)]) >>> third_square = Contour([Point(4, 4), Point(8, 4), Point(8, 8), ... Point(4, 8)]) >>> first_inner_square = Contour([Point(1, 1), Point(3, 1), Point(3, 3), ... Point(1, 3)]) >>> clockwise_first_inner_square = Contour([Point(1, 1), Point(1, 3), ... Point(3, 3), Point(3, 1)]) >>> (intersect_segment_with_multipolygon( ... Segment(Point(0, 0), Point(2, 0)), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_square, [])])) ... is intersect_segment_with_multipolygon( ... Segment(Point(0, 0), Point(4, 0)), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_square, [])])) ... is EMPTY) True >>> (intersect_segment_with_multipolygon( ... Segment(Point(0, 0), Point(2, 2)), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_square, [])])) ... == Segment(Point(1, 1), Point(2, 2))) True >>> (intersect_segment_with_multipolygon( ... Segment(Point(0, 0), Point(4, 4)), ... Multipolygon([Polygon(first_square, ... [clockwise_first_inner_square]), ... Polygon(third_square, [])])) ... == Multisegment([Segment(Point(0, 0), Point(1, 1)), ... Segment(Point(3, 3), Point(4, 4))])) True >>> (intersect_segment_with_multipolygon( ... Segment(Point(1, 1), Point(8, 8)), ... Multipolygon([Polygon(first_square, ... [clockwise_first_inner_square]), ... Polygon(third_square, [])])) ... == Multisegment([Segment(Point(3, 3), Point(4, 4)), ... Segment(Point(4, 4), Point(8, 8))])) True """ return (_mixed.Intersection(_operands.SegmentOperand(segment), _operands.MultipolygonOperand(multipolygon), _get_context() if context is None else context) .compute())
[docs]def subtract_multipolygon_from_segment(minuend: _Segment, subtrahend: _Multipolygon, *, context: _Optional[_Context] = None ) -> _Union[_Empty, _Multisegment, _Segment]: """ Returns difference of segment with multipolygon. Time complexity: ``O(segments_count * log segments_count)`` Memory complexity: ``O(segments_count)`` where ``segments_count = start_segments_count + intersections_count``, ``start_segments_count = subtrahend_edges_count + 1``, ``subtrahend_edges_count = sum(len(polygon.border.vertices)\ + sum(len(hole.vertices) for hole in polygon.holes)\ for polygon in subtrahend.polygons)``, ``intersections_count`` --- number of intersections between segment and multipolygon edges. :param minuend: segment to subtract from. :param subtrahend: multipolygon to subtract. :param context: geometric context. :returns: difference of minuend with subtrahend. >>> from ground.base import get_context >>> context = get_context() >>> EMPTY = context.empty >>> Contour = context.contour_cls >>> Multipolygon = context.multipolygon_cls >>> Multisegment = context.multisegment_cls >>> Point = context.point_cls >>> Polygon = context.polygon_cls >>> Segment = context.segment_cls >>> first_square = Contour([Point(0, 0), Point(4, 0), Point(4, 4), ... Point(0, 4)]) >>> second_square = Contour([Point(4, 0), Point(8, 0), Point(8, 4), ... Point(4, 4)]) >>> third_square = Contour([Point(4, 4), Point(8, 4), Point(8, 8), ... Point(4, 8)]) >>> first_inner_square = Contour([Point(1, 1), Point(3, 1), Point(3, 3), ... Point(1, 3)]) >>> clockwise_first_inner_square = Contour([Point(1, 1), Point(1, 3), ... Point(3, 3), Point(3, 1)]) >>> (subtract_multipolygon_from_segment( ... Segment(Point(0, 0), Point(4, 0)), ... Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])])) ... is EMPTY) True >>> (subtract_multipolygon_from_segment( ... Segment(Point(0, 0), Point(4, 4)), ... Multipolygon([Polygon(first_square, ... [clockwise_first_inner_square]), ... Polygon(third_square, [])])) ... == Segment(Point(1, 1), Point(3, 3))) True >>> (subtract_multipolygon_from_segment( ... Segment(Point(0, 0), Point(4, 4)), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_square, [])])) ... == Multisegment([Segment(Point(0, 0), Point(1, 1)), ... Segment(Point(3, 3), Point(4, 4))])) True """ return (_mixed.Difference(_operands.SegmentOperand(minuend), _operands.MultipolygonOperand(subtrahend), _get_context() if context is None else context) .compute())
[docs]def symmetric_subtract_multipolygon_from_segment( segment: _Segment, multipolygon: _Multipolygon, *, context: _Optional[_Context] = None) -> _Union[_Mix, _Multipolygon]: """ Returns symmetric difference of segment with multipolygon. Time complexity: ``O(segments_count * log segments_count)`` Memory complexity: ``O(segments_count)`` where ``segments_count = start_segments_count + intersections_count``, ``start_segments_count = multipolygon_edges_count + 1``, ``multipolygon_edges_count = sum(len(polygon.border.vertices)\ + sum(len(hole.vertices) for hole in polygon.holes)\ for polygon in multipolygon.polygons)``, ``intersections_count`` --- number of intersections between segment and multipolygon edges. :param segment: first operand. :param multipolygon: second operand. :param context: geometric context. :returns: symmetric difference of operands. >>> from ground.base import get_context >>> context = get_context() >>> EMPTY = context.empty >>> Contour = context.contour_cls >>> Mix = context.mix_cls >>> Multipolygon = context.multipolygon_cls >>> Multisegment = context.multisegment_cls >>> Point = context.point_cls >>> Polygon = context.polygon_cls >>> Segment = context.segment_cls >>> first_square = Contour([Point(0, 0), Point(4, 0), Point(4, 4), ... Point(0, 4)]) >>> second_square = Contour([Point(4, 0), Point(8, 0), Point(8, 4), ... Point(4, 4)]) >>> third_square = Contour([Point(4, 4), Point(8, 4), Point(8, 8), ... Point(4, 8)]) >>> first_inner_square = Contour([Point(1, 1), Point(3, 1), Point(3, 3), ... Point(1, 3)]) >>> clockwise_first_inner_square = Contour([Point(1, 1), Point(1, 3), ... Point(3, 3), Point(3, 1)]) >>> (symmetric_subtract_multipolygon_from_segment( ... Segment(Point(0, 0), Point(4, 4)), ... Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])])) ... == Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])])) True >>> (symmetric_subtract_multipolygon_from_segment( ... Segment(Point(0, 0), Point(4, 4)), ... Multipolygon([Polygon(first_square, ... [clockwise_first_inner_square]), ... Polygon(third_square, [])])) ... == Mix(EMPTY, Segment(Point(1, 1), Point(3, 3)), ... Multipolygon([Polygon(first_square, ... [clockwise_first_inner_square]), ... Polygon(third_square, [])]))) True >>> (symmetric_subtract_multipolygon_from_segment( ... Segment(Point(0, 0), Point(4, 4)), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_square, [])])) ... == Mix(EMPTY, Multisegment([Segment(Point(0, 0), Point(1, 1)), ... Segment(Point(3, 3), Point(4, 4))]), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_square, [])]))) True """ return _mixed.SymmetricDifference( _operands.SegmentOperand(segment), _operands.MultipolygonOperand(multipolygon), _get_context() if context is None else context ).compute()
[docs]def unite_segment_with_multipolygon(segment: _Segment, multipolygon: _Multipolygon, *, context: _Optional[_Context] = None ) -> _Union[_Mix, _Multipolygon]: """ Returns union of segment with multipolygon. Time complexity: ``O(segments_count * log segments_count)`` Memory complexity: ``O(segments_count)`` where ``segments_count = start_segments_count + intersections_count``, ``start_segments_count = multipolygon_edges_count + 1``, ``multipolygon_edges_count = sum(len(polygon.border.vertices)\ + sum(len(hole.vertices) for hole in polygon.holes)\ for polygon in multipolygon.polygons)``, ``intersections_count`` --- number of intersections between segment and multipolygon edges. :param segment: first operand. :param multipolygon: second operand. :param context: geometric context. :returns: union of operands. >>> from ground.base import get_context >>> context = get_context() >>> EMPTY = context.empty >>> Contour = context.contour_cls >>> Mix = context.mix_cls >>> Multipolygon = context.multipolygon_cls >>> Multisegment = context.multisegment_cls >>> Point = context.point_cls >>> Polygon = context.polygon_cls >>> Segment = context.segment_cls >>> first_square = Contour([Point(0, 0), Point(4, 0), Point(4, 4), ... Point(0, 4)]) >>> second_square = Contour([Point(4, 0), Point(8, 0), Point(8, 4), ... Point(4, 4)]) >>> third_square = Contour([Point(4, 4), Point(8, 4), Point(8, 8), ... Point(4, 8)]) >>> first_inner_square = Contour([Point(1, 1), Point(3, 1), Point(3, 3), ... Point(1, 3)]) >>> clockwise_first_inner_square = Contour([Point(1, 1), Point(1, 3), ... Point(3, 3), Point(3, 1)]) >>> (unite_segment_with_multipolygon( ... Segment(Point(0, 0), Point(4, 4)), ... Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])])) ... == Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])])) True >>> (unite_segment_with_multipolygon( ... Segment(Point(0, 0), Point(4, 4)), ... Multipolygon([Polygon(first_square, ... [clockwise_first_inner_square]), ... Polygon(third_square, [])])) ... == Mix(EMPTY, Segment(Point(1, 1), Point(3, 3)), ... Multipolygon([Polygon(first_square, ... [clockwise_first_inner_square]), ... Polygon(third_square, [])]))) True >>> (unite_segment_with_multipolygon( ... Segment(Point(0, 0), Point(4, 4)), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_square, [])])) ... == Mix(EMPTY, Multisegment([Segment(Point(0, 0), Point(1, 1)), ... Segment(Point(3, 3), Point(4, 4))]), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_square, [])]))) True """ return (_mixed.Union(_operands.SegmentOperand(segment), _operands.MultipolygonOperand(multipolygon), _get_context() if context is None else context) .compute())
[docs]def segments_to_multisegment(segments: _Sequence[_Segment], *, context: _Optional[_Context] = None ) -> _Union[_Empty, _Segment, _Multisegment]: """ Returns multisegment from given segments. Time complexity: ``O(segments_count * log segments_count)`` Memory complexity: ``O(segments_count)`` where ``segments_count = segments_count + intersections_count``, ``segments_count = len(segments)``, ``intersections_count`` --- number of intersections between segments. :param segments: target segments. :param context: geometric context. :returns: multisegment from segments. >>> from ground.base import get_context >>> context = get_context() >>> Multisegment = context.multisegment_cls >>> Point = context.point_cls >>> Segment = context.segment_cls >>> (segments_to_multisegment([Segment(Point(0, 0), Point(1, 0)), ... Segment(Point(0, 1), Point(1, 0))]) ... == Multisegment([Segment(Point(0, 0), Point(1, 0)), ... Segment(Point(0, 1), Point(1, 0))])) True >>> (segments_to_multisegment([Segment(Point(0, 0), Point(2, 0)), ... Segment(Point(1, 0), Point(3, 0))]) ... == Multisegment([Segment(Point(0, 0), Point(1, 0)), ... Segment(Point(1, 0), Point(2, 0)), ... Segment(Point(2, 0), Point(3, 0))])) True """ return _linear.merge_segments( segments, _get_context() if context is None else context )
[docs]def complete_intersect_multisegments(first: _Multisegment, second: _Multisegment, *, context: _Optional[_Context] = None ) -> _Union[_Empty, _Mix, _Multipoint, _Multisegment, _Segment]: """ Returns intersection of multisegments considering cases with segments touching each other in points. Time complexity: ``O(segments_count * log segments_count)`` Memory complexity: ``O(segments_count)`` where ``segments_count = segments_count + intersections_count``, ``segments_count = len(first.segments) + len(second.segments)``, ``intersections_count`` --- number of intersections between multisegments. :param first: first operand. :param second: second operand. :param context: geometric context. :returns: intersection of operands. >>> from ground.base import get_context >>> context = get_context() >>> EMPTY = context.empty >>> Mix = context.mix_cls >>> Multipoint = context.multipoint_cls >>> Multisegment = context.multisegment_cls >>> Point = context.point_cls >>> Segment = context.segment_cls >>> (complete_intersect_multisegments( ... Multisegment([Segment(Point(0, 0), Point(1, 0)), ... Segment(Point(0, 1), Point(1, 0))]), ... Multisegment([Segment(Point(0, 0), Point(1, 0)), ... Segment(Point(0, 1), Point(1, 0))])) ... == Multisegment([Segment(Point(0, 0), Point(1, 0)), ... Segment(Point(0, 1), Point(1, 0))])) True >>> (complete_intersect_multisegments( ... Multisegment([Segment(Point(0, 0), Point(1, 0)), ... Segment(Point(0, 1), Point(1, 1))]), ... Multisegment([Segment(Point(0, 0), Point(2, 0)), ... Segment(Point(0, 0), Point(2, 2))])) ... == Mix(Multipoint([Point(1, 1)]), Segment(Point(0, 0), Point(1, 0)), ... EMPTY)) True """ return _linear.CompleteIntersection( _operands.MultisegmentOperand(first), _operands.MultisegmentOperand(second), _get_context() if context is None else context ).compute()
[docs]def intersect_multisegments(first: _Multisegment, second: _Multisegment, *, context: _Optional[_Context] = None ) -> _Union[_Empty, _Segment, _Multisegment]: """ Returns intersection of multisegments. Time complexity: ``O(segments_count * log segments_count)`` Memory complexity: ``O(segments_count)`` where ``segments_count = segments_count + intersections_count``, ``segments_count = len(first.segments) + len(second.segments)``, ``intersections_count`` --- number of intersections between multisegments. :param first: first operand. :param second: second operand. :param context: geometric context. :returns: intersection of operands. >>> from ground.base import get_context >>> context = get_context() >>> Multisegment = context.multisegment_cls >>> Point = context.point_cls >>> Segment = context.segment_cls >>> (intersect_multisegments( ... Multisegment([Segment(Point(0, 0), Point(1, 0)), ... Segment(Point(0, 1), Point(1, 0))]), ... Multisegment([Segment(Point(0, 0), Point(1, 0)), ... Segment(Point(0, 1), Point(1, 0))])) ... == Multisegment([Segment(Point(0, 0), Point(1, 0)), ... Segment(Point(0, 1), Point(1, 0))])) True >>> (intersect_multisegments( ... Multisegment([Segment(Point(0, 0), Point(1, 0)), ... Segment(Point(0, 1), Point(1, 1))]), ... Multisegment([Segment(Point(0, 0), Point(2, 0)), ... Segment(Point(0, 0), Point(2, 2))])) ... == Segment(Point(0, 0), Point(1, 0))) True """ return _linear.Intersection( _operands.MultisegmentOperand(first), _operands.MultisegmentOperand(second), _get_context() if context is None else context ).compute()
[docs]def subtract_multisegments(minuend: _Multisegment, subtrahend: _Multisegment, *, context: _Optional[_Context] = None ) -> _Union[_Empty, _Segment, _Multisegment]: """ Returns difference of multisegments. Time complexity: ``O(segments_count * log segments_count)`` Memory complexity: ``O(segments_count)`` where ``segments_count = segments_count + intersections_count``, ``segments_count = len(first.segments) + len(second.segments)``, ``intersections_count`` --- number of intersections between multisegments. :param minuend: multisegment to subtract from. :param subtrahend: multisegment to subtract. :param context: geometric context. :returns: difference between minuend and subtrahend. >>> from ground.base import get_context >>> context = get_context() >>> EMPTY = context.empty >>> Multisegment = context.multisegment_cls >>> Point = context.point_cls >>> Segment = context.segment_cls >>> (subtract_multisegments( ... Multisegment([Segment(Point(0, 0), Point(1, 0)), ... Segment(Point(0, 1), Point(1, 0))]), ... Multisegment([Segment(Point(0, 0), Point(1, 0)), ... Segment(Point(0, 1), Point(1, 0))])) ... is EMPTY) True >>> (subtract_multisegments( ... Multisegment([Segment(Point(0, 0), Point(1, 0)), ... Segment(Point(0, 1), Point(1, 1))]), ... Multisegment([Segment(Point(0, 0), Point(2, 0)), ... Segment(Point(0, 0), Point(2, 2))])) ... == Segment(Point(0, 1), Point(1, 1))) True """ return (_linear.Difference(_operands.MultisegmentOperand(minuend), _operands.MultisegmentOperand(subtrahend), _get_context() if context is None else context) .compute())
[docs]def symmetric_subtract_multisegments(first: _Multisegment, second: _Multisegment, *, context: _Optional[_Context] = None ) -> _Union[_Empty, _Segment, _Multisegment]: """ Returns symmetric difference of multisegments. Time complexity: ``O(segments_count * log segments_count)`` Memory complexity: ``O(segments_count)`` where ``segments_count = segments_count + intersections_count``, ``segments_count = len(first.segments) + len(second.segments)``, ``intersections_count`` --- number of intersections between multisegments. :param first: first operand. :param second: second operand. :param context: geometric context. :returns: symmetric difference of operands. >>> from ground.base import get_context >>> context = get_context() >>> EMPTY = context.empty >>> Multisegment = context.multisegment_cls >>> Point = context.point_cls >>> Segment = context.segment_cls >>> (symmetric_subtract_multisegments( ... Multisegment([Segment(Point(0, 0), Point(1, 0)), ... Segment(Point(0, 1), Point(1, 0))]), ... Multisegment([Segment(Point(0, 0), Point(1, 0)), ... Segment(Point(0, 1), Point(1, 0))])) ... is EMPTY) True >>> (symmetric_subtract_multisegments( ... Multisegment([Segment(Point(0, 0), Point(1, 0)), ... Segment(Point(0, 1), Point(1, 1))]), ... Multisegment([Segment(Point(0, 0), Point(2, 0)), ... Segment(Point(0, 0), Point(2, 2))])) ... == Multisegment([Segment(Point(0, 0), Point(1, 1)), ... Segment(Point(0, 1), Point(1, 1)), ... Segment(Point(1, 0), Point(2, 0)), ... Segment(Point(1, 1), Point(2, 2))])) True """ return _linear.SymmetricDifference( _operands.MultisegmentOperand(first), _operands.MultisegmentOperand(second), _get_context() if context is None else context ).compute()
[docs]def unite_multisegments(first: _Multisegment, second: _Multisegment, *, context: _Optional[_Context] = None) -> _Multisegment: """ Returns union of multisegments. Time complexity: ``O(segments_count * log segments_count)`` Memory complexity: ``O(segments_count)`` where ``segments_count = segments_count + intersections_count``, ``segments_count = len(first.segments) + len(second.segments)``, ``intersections_count`` --- number of intersections between multisegments. :param first: first operand. :param second: second operand. :param context: geometric context. :returns: union of operands. >>> from ground.base import get_context >>> context = get_context() >>> Multisegment = context.multisegment_cls >>> Point = context.point_cls >>> Segment = context.segment_cls >>> (unite_multisegments(Multisegment([Segment(Point(0, 0), Point(1, 0)), ... Segment(Point(0, 1), Point(1, 0))]), ... Multisegment([Segment(Point(0, 0), Point(1, 0)), ... Segment(Point(0, 1), Point(1, 0))])) ... == Multisegment([Segment(Point(0, 0), Point(1, 0)), ... Segment(Point(0, 1), Point(1, 0))])) True >>> (unite_multisegments(Multisegment([Segment(Point(0, 0), Point(1, 0)), ... Segment(Point(0, 1), Point(1, 1))]), ... Multisegment([Segment(Point(0, 0), Point(2, 0)), ... Segment(Point(0, 0), Point(2, 2))])) ... == Multisegment([Segment(Point(0, 0), Point(1, 0)), ... Segment(Point(0, 0), Point(1, 1)), ... Segment(Point(0, 1), Point(1, 1)), ... Segment(Point(1, 0), Point(2, 0)), ... Segment(Point(1, 1), Point(2, 2))])) True """ return (_linear.Union(_operands.MultisegmentOperand(first), _operands.MultisegmentOperand(second), _get_context() if context is None else context) .compute())
[docs]def complete_intersect_multisegment_with_polygon( multisegment: _Multisegment, polygon: _Polygon, *, context: _Optional[_Context] = None ) -> _Union[_Empty, _Mix, _Multipoint, _Multisegment, _Segment]: """ Returns intersection of multisegment with polygon considering cases with geometries touching each other in points. Time complexity: ``O(segments_count * log segments_count)`` Memory complexity: ``O(segments_count)`` where ``segments_count = start_segments_count + intersections_count``, ``start_segments_count = len(multisegment.segments)\ + polygon_edges_count``, ``polygon_edges_count = len(polygon.border.vertices)\ + sum(len(hole.vertices) for hole in polygon.holes)``, ``intersections_count`` --- number of intersections between multisegment and polygon edges. :param multisegment: multisegment to intersect with. :param polygon: polygon to intersect with. :param context: geometric context. :returns: intersection of multisegment with polygon. >>> from ground.base import get_context >>> context = get_context() >>> EMPTY = context.empty >>> Mix = context.mix_cls >>> Contour = context.contour_cls >>> Multipoint = context.multipoint_cls >>> Multisegment = context.multisegment_cls >>> Point = context.point_cls >>> Polygon = context.polygon_cls >>> Segment = context.segment_cls >>> (complete_intersect_multisegment_with_polygon( ... Multisegment([Segment(Point(0, 0), Point(1, 0)), ... Segment(Point(0, 1), Point(1, 0))]), ... Polygon(Contour([Point(0, 0), Point(1, 0), Point(0, 1)]), [])) ... == Multisegment([Segment(Point(0, 0), Point(1, 0)), ... Segment(Point(0, 1), Point(1, 0))])) True >>> (complete_intersect_multisegment_with_polygon( ... Multisegment([Segment(Point(0, 0), Point(1, 0)), ... Segment(Point(1, 1), Point(2, 2))]), ... Polygon(Contour([Point(0, 0), Point(1, 0), Point(1, 1), ... Point(0, 1)]), [])) ... == Mix(Multipoint([Point(1, 1)]), Segment(Point(0, 0), Point(1, 0)), ... EMPTY)) True """ return _mixed.CompleteIntersection( _operands.MultisegmentOperand(multisegment), _operands.PolygonOperand(polygon), _get_context() if context is None else context ).compute()
[docs]def intersect_multisegment_with_polygon( multisegment: _Multisegment, polygon: _Polygon, *, context: _Optional[_Context] = None ) -> _Union[_Empty, _Multisegment, _Segment]: """ Returns intersection of multisegment with polygon. Time complexity: ``O(segments_count * log segments_count)`` Memory complexity: ``O(segments_count)`` where ``segments_count = start_segments_count + intersections_count``, ``start_segments_count = len(multisegment.segments)\ + polygon_edges_count``, ``polygon_edges_count = len(polygon.border.vertices)\ + sum(len(hole.vertices) for hole in polygon.holes)``, ``intersections_count`` --- number of intersections between multisegment and polygon edges. :param multisegment: multisegment to intersect with. :param polygon: polygon to intersect with. :param context: geometric context. :returns: intersection of multisegment with polygon. >>> from ground.base import get_context >>> context = get_context() >>> Contour = context.contour_cls >>> Multisegment = context.multisegment_cls >>> Point = context.point_cls >>> Polygon = context.polygon_cls >>> Segment = context.segment_cls >>> (intersect_multisegment_with_polygon( ... Multisegment([Segment(Point(0, 0), Point(1, 0)), ... Segment(Point(0, 1), Point(1, 0))]), ... Polygon(Contour([Point(0, 0), Point(1, 0), Point(0, 1)]), [])) ... == Multisegment([Segment(Point(0, 0), Point(1, 0)), ... Segment(Point(0, 1), Point(1, 0))])) True >>> (intersect_multisegment_with_polygon( ... Multisegment([Segment(Point(0, 0), Point(1, 0)), ... Segment(Point(1, 1), Point(2, 2))]), ... Polygon(Contour([Point(0, 0), Point(1, 0), Point(1, 1), ... Point(0, 1)]), [])) ... == Segment(Point(0, 0), Point(1, 0))) True """ return (_mixed.Intersection(_operands.MultisegmentOperand(multisegment), _operands.PolygonOperand(polygon), _get_context() if context is None else context) .compute())
[docs]def subtract_polygon_from_multisegment( minuend: _Multisegment, subtrahend: _Polygon, *, context: _Optional[_Context] = None ) -> _Union[_Empty, _Multisegment, _Segment]: """ Returns difference of multisegment with polygon. Time complexity: ``O(segments_count * log segments_count)`` Memory complexity: ``O(segments_count)`` where ``segments_count = start_segments_count + intersections_count``, ``start_segments_count = len(minuend.segments)\ + subtrahend_edges_count``, ``subtrahend_edges_count = len(polygon.border.vertices)\ + sum(len(hole.vertices) for hole in polygon.holes)``, ``intersections_count`` --- number of intersections between multisegment and polygon edges. :param minuend: multisegment to subtract from. :param subtrahend: polygon to subtract. :param context: geometric context. :returns: difference of minuend with subtrahend. >>> from ground.base import get_context >>> context = get_context() >>> EMPTY = context.empty >>> Contour = context.contour_cls >>> Multipoint = context.multipoint_cls >>> Polygon = context.polygon_cls >>> Multisegment = context.multisegment_cls >>> Point = context.point_cls >>> Polygon = context.polygon_cls >>> Segment = context.segment_cls >>> (subtract_polygon_from_multisegment( ... Multisegment([Segment(Point(0, 0), Point(1, 0)), ... Segment(Point(0, 1), Point(1, 0))]), ... Polygon(Contour([Point(0, 0), Point(1, 0), Point(0, 1)]), [])) ... is EMPTY) True >>> (subtract_polygon_from_multisegment( ... Multisegment([Segment(Point(0, 0), Point(1, 0)), ... Segment(Point(1, 1), Point(2, 2))]), ... Polygon(Contour([Point(0, 0), Point(1, 0), Point(1, 1), ... Point(0, 1)]), [])) ... == Segment(Point(1, 1), Point(2, 2))) True """ return (_mixed.Difference(_operands.MultisegmentOperand(minuend), _operands.PolygonOperand(subtrahend), _get_context() if context is None else context) .compute())
[docs]def symmetric_subtract_polygon_from_multisegment( multisegment: _Multisegment, polygon: _Polygon, *, context: _Optional[_Context] = None) -> _Union[_Mix, _Polygon]: """ Returns symmetric difference of multisegment with polygon. Time complexity: ``O(segments_count * log segments_count)`` Memory complexity: ``O(segments_count)`` where ``segments_count = start_segments_count + intersections_count``, ``start_segments_count = len(multisegment.segments)\ + polygon_edges_count``, ``polygon_edges_count = len(polygon.border.vertices)\ + sum(len(hole.vertices) for hole in polygon.holes)``, ``intersections_count`` --- number of intersections between multisegment and polygon edges. :param multisegment: first operand. :param polygon: second operand. :param context: geometric context. :returns: symmetric difference of operands. >>> from ground.base import get_context >>> context = get_context() >>> EMPTY = context.empty >>> Contour = context.contour_cls >>> Mix = context.mix_cls >>> Polygon = context.polygon_cls >>> Multisegment = context.multisegment_cls >>> Point = context.point_cls >>> Polygon = context.polygon_cls >>> Segment = context.segment_cls >>> (symmetric_subtract_polygon_from_multisegment( ... Multisegment([Segment(Point(0, 0), Point(1, 0)), ... Segment(Point(0, 1), Point(1, 0))]), ... Polygon(Contour([Point(0, 0), Point(1, 0), Point(0, 1)]), [])) ... == Polygon(Contour([Point(0, 0), Point(1, 0), Point(0, 1)]), [])) True >>> (symmetric_subtract_polygon_from_multisegment( ... Multisegment([Segment(Point(0, 0), Point(1, 0)), ... Segment(Point(1, 1), Point(2, 2))]), ... Polygon(Contour([Point(0, 0), Point(1, 0), Point(1, 1), ... Point(0, 1)]), [])) ... == Mix(EMPTY, Segment(Point(1, 1), Point(2, 2)), ... Polygon(Contour([Point(0, 0), Point(1, 0), Point(1, 1), ... Point(0, 1)]), []))) True >>> (symmetric_subtract_polygon_from_multisegment( ... Multisegment([Segment(Point(0, 0), Point(1, 0)), ... Segment(Point(1, 0), Point(2, 0)), ... Segment(Point(1, 1), Point(2, 2))]), ... Polygon(Contour([Point(0, 0), Point(1, 0), Point(1, 1), ... Point(0, 1)]), [])) ... == Mix(EMPTY, Multisegment([Segment(Point(1, 0), Point(2, 0)), ... Segment(Point(1, 1), Point(2, 2))]), ... Polygon(Contour([Point(0, 0), Point(1, 0), Point(1, 1), ... Point(0, 1)]), []))) True """ return _mixed.SymmetricDifference( _operands.MultisegmentOperand(multisegment), _operands.PolygonOperand(polygon), _get_context() if context is None else context ).compute()
[docs]def unite_multisegment_with_polygon( multisegment: _Multisegment, polygon: _Polygon, *, context: _Optional[_Context] = None) -> _Union[_Mix, _Polygon]: """ Returns union of multisegment with polygon. Time complexity: ``O(segments_count * log segments_count)`` Memory complexity: ``O(segments_count)`` where ``segments_count = start_segments_count + intersections_count``, ``start_segments_count = len(multisegment.segments)\ + polygon_edges_count``, ``polygon_edges_count = len(polygon.border.vertices)\ + sum(len(hole.vertices) for hole in polygon.holes)``, ``intersections_count`` --- number of intersections between multisegment and polygon edges. :param multisegment: first operand. :param polygon: second operand. :param context: geometric context. :returns: union of operands. >>> from ground.base import get_context >>> context = get_context() >>> EMPTY = context.empty >>> Contour = context.contour_cls >>> Mix = context.mix_cls >>> Polygon = context.polygon_cls >>> Multisegment = context.multisegment_cls >>> Point = context.point_cls >>> Polygon = context.polygon_cls >>> Segment = context.segment_cls >>> (unite_multisegment_with_polygon( ... Multisegment([Segment(Point(0, 0), Point(1, 0)), ... Segment(Point(0, 1), Point(1, 0))]), ... Polygon(Contour([Point(0, 0), Point(1, 0), Point(0, 1)]), [])) ... == Polygon(Contour([Point(0, 0), Point(1, 0), Point(0, 1)]), [])) True >>> (unite_multisegment_with_polygon( ... Multisegment([Segment(Point(0, 0), Point(1, 0)), ... Segment(Point(1, 1), Point(2, 2))]), ... Polygon(Contour([Point(0, 0), Point(1, 0), Point(1, 1), ... Point(0, 1)]), [])) ... == Mix(EMPTY, Segment(Point(1, 1), Point(2, 2)), ... Polygon(Contour([Point(0, 0), Point(1, 0), Point(1, 1), ... Point(0, 1)]), []))) True >>> (unite_multisegment_with_polygon( ... Multisegment([Segment(Point(0, 0), Point(1, 0)), ... Segment(Point(1, 0), Point(2, 0)), ... Segment(Point(1, 1), Point(2, 2))]), ... Polygon(Contour([Point(0, 0), Point(1, 0), Point(1, 1), ... Point(0, 1)]), [])) ... == Mix(EMPTY, Multisegment([Segment(Point(1, 0), Point(2, 0)), ... Segment(Point(1, 1), Point(2, 2))]), ... Polygon(Contour([Point(0, 0), Point(1, 0), Point(1, 1), ... Point(0, 1)]), []))) True """ return (_mixed.Union(_operands.MultisegmentOperand(multisegment), _operands.PolygonOperand(polygon), _get_context() if context is None else context) .compute())
[docs]def complete_intersect_multisegment_with_multipolygon( multisegment: _Multisegment, multipolygon: _Multipolygon, *, context: _Optional[_Context] = None ) -> _Union[_Empty, _Mix, _Multipoint, _Multisegment, _Segment]: """ Returns intersection of multisegment with multipolygon considering cases with geometries touching each other in points. Time complexity: ``O(segments_count * log segments_count)`` Memory complexity: ``O(segments_count)`` where ``segments_count = start_segments_count + intersections_count``, ``start_segments_count = len(multisegment.segments)\ + multipolygon_edges_count``, ``multipolygon_edges_count = sum(len(polygon.border.vertices)\ + sum(len(hole.vertices) for hole in polygon.holes)\ for polygon in multipolygon.polygons)``, ``intersections_count`` --- number of intersections between multisegment and multipolygon edges. :param multisegment: multisegment to intersect with. :param multipolygon: multipolygon to intersect with. :param context: geometric context. :returns: intersection of multisegment with multipolygon. >>> from ground.base import get_context >>> context = get_context() >>> EMPTY = context.empty >>> Mix = context.mix_cls >>> Contour = context.contour_cls >>> Multipoint = context.multipoint_cls >>> Multipolygon = context.multipolygon_cls >>> Multisegment = context.multisegment_cls >>> Point = context.point_cls >>> Polygon = context.polygon_cls >>> Segment = context.segment_cls >>> first_square = Contour([Point(0, 0), Point(4, 0), Point(4, 4), ... Point(0, 4)]) >>> second_square = Contour([Point(4, 0), Point(8, 0), Point(8, 4), ... Point(4, 4)]) >>> third_square = Contour([Point(4, 4), Point(8, 4), Point(8, 8), ... Point(4, 8)]) >>> first_inner_square = Contour([Point(1, 1), Point(3, 1), Point(3, 3), ... Point(1, 3)]) >>> clockwise_first_inner_square = Contour([Point(1, 1), Point(1, 3), ... Point(3, 3), Point(3, 1)]) >>> (complete_intersect_multisegment_with_multipolygon( ... Multisegment([Segment(Point(0, 0), Point(2, 0)), ... Segment(Point(0, 0), Point(0, 2))]), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_square, [])])) ... is EMPTY) True >>> (complete_intersect_multisegment_with_multipolygon( ... Multisegment([Segment(Point(0, 0), Point(4, 0)), ... Segment(Point(0, 0), Point(0, 4))]), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_square, [])])) ... == Multipoint([Point(4, 0)])) True >>> (complete_intersect_multisegment_with_multipolygon( ... Multisegment([Segment(Point(0, 0), Point(2, 0)), ... Segment(Point(0, 0), Point(2, 2))]), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_square, [])])) ... == Segment(Point(1, 1), Point(2, 2))) True >>> (complete_intersect_multisegment_with_multipolygon( ... Multisegment([Segment(Point(0, 0), Point(4, 0)), ... Segment(Point(0, 0), Point(4, 4))]), ... Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])])) ... == Multisegment([Segment(Point(0, 0), Point(4, 0)), ... Segment(Point(0, 0), Point(4, 4))])) True >>> (complete_intersect_multisegment_with_multipolygon( ... Multisegment([Segment(Point(0, 0), Point(4, 0)), ... Segment(Point(0, 0), Point(4, 4))]), ... Multipolygon([Polygon(first_square, ... [clockwise_first_inner_square]), ... Polygon(third_square, [])])) ... == Multisegment([Segment(Point(0, 0), Point(4, 0)), ... Segment(Point(0, 0), Point(1, 1)), ... Segment(Point(3, 3), Point(4, 4))])) True >>> (complete_intersect_multisegment_with_multipolygon( ... Multisegment([Segment(Point(0, 0), Point(4, 0)), ... Segment(Point(0, 0), Point(4, 4))]), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_square, [])])) ... == Mix(Multipoint([Point(4, 0), Point(4, 4)]), ... Segment(Point(1, 1), Point(3, 3)), EMPTY)) True """ return _mixed.CompleteIntersection( _operands.MultisegmentOperand(multisegment), _operands.MultipolygonOperand(multipolygon), _get_context() if context is None else context ).compute()
[docs]def intersect_multisegment_with_multipolygon( multisegment: _Multisegment, multipolygon: _Multipolygon, *, context: _Optional[_Context] = None ) -> _Union[_Empty, _Multisegment, _Segment]: """ Returns intersection of multisegment with multipolygon. Time complexity: ``O(segments_count * log segments_count)`` Memory complexity: ``O(segments_count)`` where ``segments_count = start_segments_count + intersections_count``, ``start_segments_count = len(multisegment.segments)\ + multipolygon_edges_count``, ``multipolygon_edges_count = sum(len(polygon.border.vertices)\ + sum(len(hole.vertices) for hole in polygon.holes)\ for polygon in multipolygon.polygons)``, ``intersections_count`` --- number of intersections between multisegment and multipolygon edges. :param multisegment: multisegment to intersect with. :param multipolygon: multipolygon to intersect with. :param context: geometric context. :returns: intersection of multisegment with multipolygon. >>> from ground.base import get_context >>> context = get_context() >>> EMPTY = context.empty >>> Contour = context.contour_cls >>> Multipolygon = context.multipolygon_cls >>> Multisegment = context.multisegment_cls >>> Point = context.point_cls >>> Polygon = context.polygon_cls >>> Segment = context.segment_cls >>> first_square = Contour([Point(0, 0), Point(4, 0), Point(4, 4), ... Point(0, 4)]) >>> second_square = Contour([Point(4, 0), Point(8, 0), Point(8, 4), ... Point(4, 4)]) >>> third_square = Contour([Point(4, 4), Point(8, 4), Point(8, 8), ... Point(4, 8)]) >>> first_inner_square = Contour([Point(1, 1), Point(3, 1), Point(3, 3), ... Point(1, 3)]) >>> clockwise_first_inner_square = Contour([Point(1, 1), Point(1, 3), ... Point(3, 3), Point(3, 1)]) >>> (intersect_multisegment_with_multipolygon( ... Multisegment([Segment(Point(0, 0), Point(4, 0)), ... Segment(Point(0, 0), Point(0, 4))]), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_square, [])])) ... is EMPTY) True >>> (intersect_multisegment_with_multipolygon( ... Multisegment([Segment(Point(0, 0), Point(4, 0)), ... Segment(Point(0, 0), Point(4, 4))]), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_square, [])])) ... == Segment(Point(1, 1), Point(3, 3))) True >>> (intersect_multisegment_with_multipolygon( ... Multisegment([Segment(Point(0, 0), Point(4, 0)), ... Segment(Point(0, 0), Point(4, 4))]), ... Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])])) ... == Multisegment([Segment(Point(0, 0), Point(4, 0)), ... Segment(Point(0, 0), Point(4, 4))])) True >>> (intersect_multisegment_with_multipolygon( ... Multisegment([Segment(Point(0, 0), Point(4, 0)), ... Segment(Point(0, 0), Point(4, 4))]), ... Multipolygon([Polygon(first_square, ... [clockwise_first_inner_square]), ... Polygon(third_square, [])])) ... == Multisegment([Segment(Point(0, 0), Point(4, 0)), ... Segment(Point(0, 0), Point(1, 1)), ... Segment(Point(3, 3), Point(4, 4))])) True """ return (_mixed.Intersection(_operands.MultisegmentOperand(multisegment), _operands.MultipolygonOperand(multipolygon), _get_context() if context is None else context) .compute())
[docs]def subtract_multipolygon_from_multisegment( minuend: _Multisegment, subtrahend: _Multipolygon, *, context: _Optional[_Context] = None ) -> _Union[_Empty, _Multisegment, _Segment]: """ Returns difference of multisegment with multipolygon. Time complexity: ``O(segments_count * log segments_count)`` Memory complexity: ``O(segments_count)`` where ``segments_count = start_segments_count + intersections_count``, ``start_segments_count = len(minuend.segments)\ + multipolygon_edges_count``, ``subtrahend_edges_count = sum(len(polygon.border.vertices)\ + sum(len(hole.vertices) for hole in polygon.holes)\ for polygon in subtrahend.polygons)``, ``intersections_count`` --- number of intersections between multisegment and multipolygon edges. :param minuend: multisegment to subtract from. :param subtrahend: multipolygon to subtract. :param context: geometric context. :returns: difference of minuend with subtrahend. >>> from ground.base import get_context >>> context = get_context() >>> EMPTY = context.empty >>> Contour = context.contour_cls >>> Multipolygon = context.multipolygon_cls >>> Multisegment = context.multisegment_cls >>> Point = context.point_cls >>> Polygon = context.polygon_cls >>> Segment = context.segment_cls >>> first_square = Contour([Point(0, 0), Point(4, 0), Point(4, 4), ... Point(0, 4)]) >>> second_square = Contour([Point(4, 0), Point(8, 0), Point(8, 4), ... Point(4, 4)]) >>> third_square = Contour([Point(4, 4), Point(8, 4), Point(8, 8), ... Point(4, 8)]) >>> first_inner_square = Contour([Point(1, 1), Point(3, 1), Point(3, 3), ... Point(1, 3)]) >>> clockwise_first_inner_square = Contour([Point(1, 1), Point(1, 3), ... Point(3, 3), Point(3, 1)]) >>> (subtract_multipolygon_from_multisegment( ... Multisegment([Segment(Point(0, 0), Point(4, 0)), ... Segment(Point(0, 0), Point(4, 4))]), ... Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])])) ... is EMPTY) True >>> (subtract_multipolygon_from_multisegment( ... Multisegment([Segment(Point(0, 0), Point(4, 0)), ... Segment(Point(0, 0), Point(4, 4))]), ... Multipolygon([Polygon(first_square, [clockwise_first_inner_square]), ... Polygon(third_square, [])])) ... == Segment(Point(1, 1), Point(3, 3))) True >>> (subtract_multipolygon_from_multisegment( ... Multisegment([Segment(Point(0, 0), Point(4, 0)), ... Segment(Point(0, 0), Point(4, 4))]), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_square, [])])) ... == Multisegment([Segment(Point(0, 0), Point(1, 1)), ... Segment(Point(0, 0), Point(4, 0)), ... Segment(Point(3, 3), Point(4, 4))])) True """ return (_mixed.Difference(_operands.MultisegmentOperand(minuend), _operands.MultipolygonOperand(subtrahend), _get_context() if context is None else context) .compute())
[docs]def symmetric_subtract_multipolygon_from_multisegment( multisegment: _Multisegment, multipolygon: _Multipolygon, *, context: _Optional[_Context] = None) -> _Union[_Mix, _Multipolygon]: """ Returns symmetric difference of multisegment with multipolygon. Time complexity: ``O(segments_count * log segments_count)`` Memory complexity: ``O(segments_count)`` where ``segments_count = start_segments_count + intersections_count``, ``start_segments_count = len(multisegment.segments)\ + multipolygon_edges_count``, ``multipolygon_edges_count = len(multipolygon.border.vertices)\ + sum(len(hole.vertices) for hole in multipolygon.holes)``, ``intersections_count`` --- number of intersections between multisegment and multipolygon edges. :param multisegment: first operand. :param multipolygon: second operand. :param context: geometric context. :returns: symmetric difference of operands. >>> from ground.base import get_context >>> context = get_context() >>> EMPTY = context.empty >>> Contour = context.contour_cls >>> Mix = context.mix_cls >>> Multipolygon = context.multipolygon_cls >>> Multisegment = context.multisegment_cls >>> Point = context.point_cls >>> Polygon = context.polygon_cls >>> Segment = context.segment_cls >>> first_square = Contour([Point(0, 0), Point(4, 0), Point(4, 4), ... Point(0, 4)]) >>> second_square = Contour([Point(4, 0), Point(8, 0), Point(8, 4), ... Point(4, 4)]) >>> third_square = Contour([Point(4, 4), Point(8, 4), Point(8, 8), ... Point(4, 8)]) >>> first_inner_square = Contour([Point(1, 1), Point(3, 1), Point(3, 3), ... Point(1, 3)]) >>> clockwise_first_inner_square = Contour([Point(1, 1), Point(1, 3), ... Point(3, 3), Point(3, 1)]) >>> (symmetric_subtract_multipolygon_from_multisegment( ... Multisegment([Segment(Point(0, 0), Point(4, 0)), ... Segment(Point(0, 0), Point(4, 4))]), ... Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])])) ... == Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])])) True >>> (symmetric_subtract_multipolygon_from_multisegment( ... Multisegment([Segment(Point(0, 0), Point(4, 0)), ... Segment(Point(0, 0), Point(4, 4))]), ... Multipolygon([Polygon(first_square, [clockwise_first_inner_square]), ... Polygon(third_square, [])])) ... == Mix(EMPTY, Segment(Point(1, 1), Point(3, 3)), ... Multipolygon([Polygon(first_square, ... [clockwise_first_inner_square]), ... Polygon(third_square, [])]))) True >>> (symmetric_subtract_multipolygon_from_multisegment( ... Multisegment([Segment(Point(0, 0), Point(4, 0)), ... Segment(Point(0, 0), Point(4, 4))]), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_square, [])])) ... == Mix(EMPTY, Multisegment([Segment(Point(0, 0), Point(4, 0)), ... Segment(Point(0, 0), Point(1, 1)), ... Segment(Point(3, 3), Point(4, 4))]), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_square, [])]))) True """ return _mixed.SymmetricDifference( _operands.MultisegmentOperand(multisegment), _operands.MultipolygonOperand(multipolygon), _get_context() if context is None else context ).compute()
[docs]def unite_multisegment_with_multipolygon( multisegment: _Multisegment, multipolygon: _Multipolygon, *, context: _Optional[_Context] = None) -> _Union[_Mix, _Multipolygon]: """ Returns union of multisegment with multipolygon. Time complexity: ``O(segments_count * log segments_count)`` Memory complexity: ``O(segments_count)`` where ``segments_count = start_segments_count + intersections_count``, ``start_segments_count = len(multisegment.segments)\ + multipolygon_edges_count``, ``multipolygon_edges_count = len(multipolygon.border.vertices)\ + sum(len(hole.vertices) for hole in multipolygon.holes)``, ``intersections_count`` --- number of intersections between multisegment and multipolygon edges. :param multisegment: first operand. :param multipolygon: second operand. :param context: geometric context. :returns: union of operands. >>> from ground.base import get_context >>> context = get_context() >>> EMPTY = context.empty >>> Contour = context.contour_cls >>> Mix = context.mix_cls >>> Multipolygon = context.multipolygon_cls >>> Multisegment = context.multisegment_cls >>> Point = context.point_cls >>> Polygon = context.polygon_cls >>> Segment = context.segment_cls >>> first_square = Contour([Point(0, 0), Point(4, 0), Point(4, 4), ... Point(0, 4)]) >>> second_square = Contour([Point(4, 0), Point(8, 0), Point(8, 4), ... Point(4, 4)]) >>> third_square = Contour([Point(4, 4), Point(8, 4), Point(8, 8), ... Point(4, 8)]) >>> first_inner_square = Contour([Point(1, 1), Point(3, 1), Point(3, 3), ... Point(1, 3)]) >>> clockwise_first_inner_square = Contour([Point(1, 1), Point(1, 3), ... Point(3, 3), Point(3, 1)]) >>> (unite_multisegment_with_multipolygon( ... Multisegment([Segment(Point(0, 0), Point(4, 0)), ... Segment(Point(0, 0), Point(4, 4))]), ... Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])])) ... == Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])])) True >>> (unite_multisegment_with_multipolygon( ... Multisegment([Segment(Point(0, 0), Point(4, 0)), ... Segment(Point(0, 0), Point(4, 4))]), ... Multipolygon([Polygon(first_square, [clockwise_first_inner_square]), ... Polygon(third_square, [])])) ... == Mix(EMPTY, Segment(Point(1, 1), Point(3, 3)), ... Multipolygon([Polygon(first_square, ... [clockwise_first_inner_square]), ... Polygon(third_square, [])]))) True >>> (unite_multisegment_with_multipolygon( ... Multisegment([Segment(Point(0, 0), Point(4, 0)), ... Segment(Point(0, 0), Point(4, 4))]), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_square, [])])) ... == Mix(EMPTY, Multisegment([Segment(Point(0, 0), Point(4, 0)), ... Segment(Point(0, 0), Point(1, 1)), ... Segment(Point(3, 3), Point(4, 4))]), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_square, [])]))) True """ return _mixed.Union( _operands.MultisegmentOperand(multisegment), _operands.MultipolygonOperand(multipolygon), _get_context() if context is None else context ).compute()
[docs]def complete_intersect_regions(first: _Region, second: _Region, *, context: _Optional[_Context] = None ) -> _Union[_Empty, _Mix, _Multipoint, _Multipolygon, _Multisegment, _Polygon, _Segment]: """ Returns intersection of regions considering cases with regions touching each other in points/segments. Time complexity: ``O(segments_count * log segments_count)`` Memory complexity: ``O(segments_count)`` where ``segments_count = edges_count + intersections_count``, ``edges_count = len(first.vertices) + len(second.vertices)``, ``intersections_count`` --- number of intersections between regions edges. :param first: first operand. :param second: second operand. :param context: geometric context. :returns: intersection of operands. >>> from ground.base import get_context >>> context = get_context() >>> EMPTY = context.empty >>> Contour = context.contour_cls >>> Mix = context.mix_cls >>> Multipoint = context.multipoint_cls >>> Multipolygon = context.multipolygon_cls >>> Multisegment = context.multisegment_cls >>> Point = context.point_cls >>> Polygon = context.polygon_cls >>> Segment = context.segment_cls >>> first_square = Contour([Point(0, 0), Point(4, 0), Point(4, 4), ... Point(0, 4)]) >>> second_square = Contour([Point(4, 0), Point(8, 0), Point(8, 4), ... Point(4, 4)]) >>> third_square = Contour([Point(4, 4), Point(8, 4), Point(8, 8), ... Point(4, 8)]) >>> first_inner_square = Contour([Point(1, 1), Point(3, 1), Point(3, 3), ... Point(1, 3)]) >>> (complete_intersect_regions(first_inner_square, second_square) ... is EMPTY) True >>> (complete_intersect_regions(first_square, third_square) ... == Multipoint([Point(4, 4)])) True >>> (complete_intersect_regions(first_square, second_square) ... == Segment(Point(4, 0), Point(4, 4))) True >>> (complete_intersect_regions(first_square, first_square) ... == Polygon(first_square, [])) True """ return _holeless.CompleteIntersection( _operands.RegionOperand(first), _operands.RegionOperand(second), _get_context() if context is None else context ).compute()
[docs]def intersect_regions(first: _Region, second: _Region, *, context: _Optional[_Context] = None ) -> _Union[_Empty, _Multipolygon, _Polygon]: """ Returns intersection of regions. Time complexity: ``O(segments_count * log segments_count)`` Memory complexity: ``O(segments_count)`` where ``segments_count = edges_count + intersections_count``, ``edges_count = len(first.vertices) + len(second.vertices)``, ``intersections_count`` --- number of intersections between regions edges. :param first: first operand. :param second: second operand. :param context: geometric context. :returns: intersection of operands. >>> from ground.base import get_context >>> context = get_context() >>> EMPTY = context.empty >>> Contour = context.contour_cls >>> Multipolygon = context.multipolygon_cls >>> Point = context.point_cls >>> Polygon = context.polygon_cls >>> first_square = Contour([Point(0, 0), Point(4, 0), Point(4, 4), ... Point(0, 4)]) >>> second_square = Contour([Point(4, 0), Point(8, 0), Point(8, 4), ... Point(4, 4)]) >>> third_square = Contour([Point(4, 4), Point(8, 4), Point(8, 8), ... Point(4, 8)]) >>> first_inner_square = Contour([Point(1, 1), Point(3, 1), Point(3, 3), ... Point(1, 3)]) >>> (intersect_regions(first_inner_square, second_square) ... is intersect_regions(first_square, third_square) ... is intersect_regions(first_square, second_square) ... is EMPTY) True >>> (intersect_regions(first_square, first_square) ... == Polygon(first_square, [])) True """ return _holeless.Intersection( _operands.RegionOperand(first), _operands.RegionOperand(second), _get_context() if context is None else context ).compute()
[docs]def complete_intersect_region_with_multiregion( region: _Region, multiregion: _Multiregion, *, context: _Optional[_Context] = None ) -> _Union[_Empty, _Mix, _Multipoint, _Multipolygon, _Multisegment, _Polygon, _Segment]: """ Returns intersection of region with multiregion considering cases with regions touching each other in points/segments. Time complexity: ``O(segments_count * log segments_count)`` Memory complexity: ``O(segments_count)`` where ``segments_count = edges_count + intersections_count``, ``edges_count = len(region.vertices) + multiregion_edges_count``, ``multiregion_edges_count = sum(len(region.vertices)\ for region in multiregion)``, ``intersections_count`` --- number of intersections between regions edges. :param region: first operand. :param multiregion: second operand. :param context: geometric context. :returns: intersection of operands. >>> from ground.base import get_context >>> context = get_context() >>> EMPTY = context.empty >>> Contour = context.contour_cls >>> Mix = context.mix_cls >>> Multipoint = context.multipoint_cls >>> Multipolygon = context.multipolygon_cls >>> Multisegment = context.multisegment_cls >>> Point = context.point_cls >>> Polygon = context.polygon_cls >>> Segment = context.segment_cls >>> first_square = Contour([Point(0, 0), Point(4, 0), Point(4, 4), ... Point(0, 4)]) >>> second_square = Contour([Point(4, 0), Point(8, 0), Point(8, 4), ... Point(4, 4)]) >>> third_square = Contour([Point(4, 4), Point(8, 4), Point(8, 8), ... Point(4, 8)]) >>> first_inner_square = Contour([Point(1, 1), Point(3, 1), Point(3, 3), ... Point(1, 3)]) >>> second_inner_square = Contour([Point(5, 1), Point(7, 1), Point(7, 3), ... Point(5, 3)]) >>> (complete_intersect_region_with_multiregion( ... second_inner_square, [first_square, third_square]) ... is EMPTY) True >>> (complete_intersect_region_with_multiregion( ... first_square, [second_inner_square, third_square]) ... == Multipoint([Point(4, 4)])) True >>> (complete_intersect_region_with_multiregion( ... second_square, [first_square, third_square]) ... == Multisegment([Segment(Point(4, 0), Point(4, 4)), ... Segment(Point(4, 4), Point(8, 4))])) True >>> (complete_intersect_region_with_multiregion( ... first_square, [first_inner_square, second_inner_square]) ... == Polygon(first_inner_square, [])) True >>> (complete_intersect_region_with_multiregion( ... first_square, [first_inner_square, third_square]) ... == Mix(Multipoint([Point(4, 4)]), EMPTY, ... Polygon(first_inner_square, []))) True >>> (complete_intersect_region_with_multiregion( ... first_square, [first_inner_square, second_square]) ... == Mix(EMPTY, Segment(Point(4, 0), Point(4, 4)), ... Polygon(first_inner_square, []))) True """ return _holeless.CompleteIntersection( _operands.RegionOperand(region), _operands.MultiregionOperand(multiregion), _get_context() if context is None else context ).compute()
[docs]def intersect_region_with_multiregion( region: _Region, multiregion: _Multiregion, *, context: _Optional[_Context] = None ) -> _Union[_Empty, _Multipolygon, _Polygon]: """ Returns intersection of region with multiregion. Time complexity: ``O(segments_count * log segments_count)`` Memory complexity: ``O(segments_count)`` where ``segments_count = edges_count + intersections_count``, ``edges_count = len(region.vertices) + multiregion_edges_count``, ``multiregion_edges_count = sum(len(region.vertices)\ for region in multiregion)``, ``intersections_count`` --- number of intersections between regions edges. :param region: first operand. :param multiregion: second operand. :param context: geometric context. :returns: intersection of operands. >>> from ground.base import get_context >>> context = get_context() >>> EMPTY = context.empty >>> Contour = context.contour_cls >>> Multipolygon = context.multipolygon_cls >>> Point = context.point_cls >>> Polygon = context.polygon_cls >>> first_square = Contour([Point(0, 0), Point(4, 0), Point(4, 4), ... Point(0, 4)]) >>> second_square = Contour([Point(4, 0), Point(8, 0), Point(8, 4), ... Point(4, 4)]) >>> third_square = Contour([Point(4, 4), Point(8, 4), Point(8, 8), ... Point(4, 8)]) >>> first_inner_square = Contour([Point(1, 1), Point(3, 1), Point(3, 3), ... Point(1, 3)]) >>> second_inner_square = Contour([Point(5, 1), Point(7, 1), Point(7, 3), ... Point(5, 3)]) >>> (intersect_region_with_multiregion( ... second_inner_square, [first_square, third_square]) ... is intersect_region_with_multiregion( ... first_square, [second_inner_square, third_square]) ... is intersect_region_with_multiregion( ... second_square, [first_square, third_square]) ... is EMPTY) True >>> (intersect_region_with_multiregion( ... first_square, [first_inner_square, second_inner_square]) ... == intersect_region_with_multiregion( ... first_square, [first_inner_square, third_square]) ... == intersect_region_with_multiregion( ... first_square, [first_inner_square, second_square]) ... == Polygon(first_inner_square, [])) True """ return _holeless.Intersection( _operands.RegionOperand(region), _operands.MultiregionOperand(multiregion), _get_context() if context is None else context ).compute()
[docs]def complete_intersect_multiregions(first: _Multiregion, second: _Multiregion, *, context: _Optional[_Context] = None ) -> _Union[_Empty, _Mix, _Multipoint, _Multipolygon, _Multisegment, _Polygon, _Segment]: """ Returns intersection of multiregions considering cases with regions touching each other in points/segments. Time complexity: ``O(segments_count * log segments_count)`` Memory complexity: ``O(segments_count)`` where ``segments_count = edges_count + intersections_count``, ``edges_count = first_edges_count + second_edges_count``, ``first_edges_count = sum(len(region.vertices) for region in first)``, ``second_edges_count = sum(len(region.vertices) for region in second)``, ``intersections_count`` --- number of intersections between multiregions edges. :param first: first operand. :param second: second operand. :param context: geometric context. :returns: intersection of operands. >>> from ground.base import get_context >>> context = get_context() >>> EMPTY = context.empty >>> Contour = context.contour_cls >>> Mix = context.mix_cls >>> Multipoint = context.multipoint_cls >>> Multipolygon = context.multipolygon_cls >>> Multisegment = context.multisegment_cls >>> Point = context.point_cls >>> Polygon = context.polygon_cls >>> Segment = context.segment_cls >>> first_square = Contour([Point(0, 0), Point(4, 0), Point(4, 4), ... Point(0, 4)]) >>> second_square = Contour([Point(4, 0), Point(8, 0), Point(8, 4), ... Point(4, 4)]) >>> third_square = Contour([Point(4, 4), Point(8, 4), Point(8, 8), ... Point(4, 8)]) >>> fourth_square = Contour([Point(0, 4), Point(4, 4), Point(4, 8), ... Point(0, 8)]) >>> first_inner_square = Contour([Point(1, 1), Point(3, 1), Point(3, 3), ... Point(1, 3)]) >>> second_inner_square = Contour([Point(5, 1), Point(7, 1), Point(7, 3), ... Point(5, 3)]) >>> third_inner_square = Contour([Point(5, 5), Point(7, 5), Point(7, 7), ... Point(5, 7)]) >>> (complete_intersect_multiregions( ... [first_inner_square, third_inner_square], ... [second_square, fourth_square]) ... is EMPTY) True >>> (complete_intersect_multiregions([first_square, third_square], ... [second_square, fourth_square]) ... == Multisegment([Segment(Point(0, 4), Point(4, 4)), ... Segment(Point(4, 0), Point(4, 4)), ... Segment(Point(4, 4), Point(8, 4)), ... Segment(Point(4, 4), Point(4, 8))])) True >>> (complete_intersect_multiregions([first_square, second_inner_square], ... [first_inner_square, second_square]) ... == Mix(EMPTY, Segment(Point(4, 0), Point(4, 4)), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_inner_square, [])]))) True >>> (complete_intersect_multiregions([first_square, third_inner_square], ... [first_inner_square, third_square]) ... == Mix(Multipoint([Point(4, 4)]), EMPTY, ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_inner_square, [])]))) True >>> (complete_intersect_multiregions( ... [first_square, third_square], ... [first_inner_square, third_inner_square]) ... == complete_intersect_multiregions( ... [first_inner_square, third_inner_square], ... [first_square, third_square]) ... == complete_intersect_multiregions( ... [first_square, third_inner_square], ... [first_inner_square, third_inner_square]) ... == complete_intersect_multiregions( ... [first_inner_square, third_inner_square], ... [first_square, third_inner_square]) ... == complete_intersect_multiregions( ... [first_inner_square, third_inner_square], ... [first_inner_square, second_inner_square, third_inner_square]) ... == complete_intersect_multiregions( ... [first_inner_square, second_inner_square, third_inner_square], ... [first_inner_square, third_inner_square]) ... == Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_inner_square, [])])) True >>> (complete_intersect_multiregions([first_square, third_square], ... [first_square, third_square]) ... == Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])])) True """ return _holeless.CompleteIntersection( _operands.MultiregionOperand(first), _operands.MultiregionOperand(second), _get_context() if context is None else context ).compute()
[docs]def intersect_multiregions(first: _Multiregion, second: _Multiregion, *, context: _Optional[_Context] = None ) -> _Union[_Empty, _Multipolygon, _Polygon]: """ Returns intersection of multiregions. Time complexity: ``O(segments_count * log segments_count)`` Memory complexity: ``O(segments_count)`` where ``segments_count = edges_count + intersections_count``, ``edges_count = first_edges_count + second_edges_count``, ``first_edges_count = sum(len(region.vertices) for region in first)``, ``second_edges_count = sum(len(region.vertices) for region in second)``, ``intersections_count`` --- number of intersections between multiregions edges. :param first: first operand. :param second: second operand. :param context: geometric context. :returns: intersection of operands. >>> from ground.base import get_context >>> context = get_context() >>> EMPTY = context.empty >>> Contour = context.contour_cls >>> Multipolygon = context.multipolygon_cls >>> Point = context.point_cls >>> Polygon = context.polygon_cls >>> first_square = Contour([Point(0, 0), Point(4, 0), Point(4, 4), ... Point(0, 4)]) >>> second_square = Contour([Point(4, 0), Point(8, 0), Point(8, 4), ... Point(4, 4)]) >>> third_square = Contour([Point(4, 4), Point(8, 4), Point(8, 8), ... Point(4, 8)]) >>> fourth_square = Contour([Point(0, 4), Point(4, 4), Point(4, 8), ... Point(0, 8)]) >>> first_inner_square = Contour([Point(1, 1), Point(3, 1), Point(3, 3), ... Point(1, 3)]) >>> second_inner_square = Contour([Point(5, 1), Point(7, 1), Point(7, 3), ... Point(5, 3)]) >>> third_inner_square = Contour([Point(5, 5), Point(7, 5), Point(7, 7), ... Point(5, 7)]) >>> (intersect_multiregions([first_inner_square, third_inner_square], ... [second_square, fourth_square]) ... is intersect_multiregions([first_square, third_square], ... [second_square, fourth_square]) ... is EMPTY) True >>> (intersect_multiregions([first_square, third_inner_square], ... [first_inner_square, third_square]) ... == intersect_multiregions([first_square, third_square], ... [first_inner_square, third_inner_square]) ... == intersect_multiregions([first_inner_square, third_inner_square], ... [first_square, third_square]) ... == Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_inner_square, [])])) True >>> (intersect_multiregions([first_square, second_inner_square], ... [first_inner_square, second_inner_square]) ... == intersect_multiregions([first_inner_square, second_inner_square], ... [first_square, second_inner_square]) ... == intersect_multiregions( ... [first_inner_square, second_inner_square], ... [first_inner_square, second_inner_square, third_inner_square]) ... == intersect_multiregions( ... [first_inner_square, second_inner_square, third_inner_square], ... [first_inner_square, second_inner_square]) ... == Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_inner_square, [])])) True >>> (intersect_multiregions([first_square, third_square], ... [first_square, third_square]) ... == Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])])) True """ return _holeless.Intersection( _operands.MultiregionOperand(first), _operands.MultiregionOperand(second), _get_context() if context is None else context ).compute()
[docs]def complete_intersect_polygons(first: _Polygon, second: _Polygon, *, context: _Optional[_Context] = None ) -> _Union[_Empty, _Mix, _Multipoint, _Multisegment, _Polygon, _Segment]: """ Returns intersection of polygons considering cases with polygons touching each other in points/segments. Time complexity: ``O(segments_count * log segments_count)`` Memory complexity: ``O(segments_count)`` where ``segments_count = edges_count + intersections_count``, ``edges_count = first_edges_count + second_edges_count``, ``first_edges_count = len(first.border.vertices)\ + sum(len(hole.vertices) for hole in first.holes)``, ``second_edges_count = len(second.border.vertices)\ + sum(len(hole.vertices) for hole in second.holes)``, ``intersections_count`` --- number of intersections between polygons edges. :param first: first operand. :param second: second operand. :param context: geometric context. :returns: intersection of operands. >>> from ground.base import get_context >>> context = get_context() >>> EMPTY = context.empty >>> Contour = context.contour_cls >>> Mix = context.mix_cls >>> Multipoint = context.multipoint_cls >>> Multipolygon = context.multipolygon_cls >>> Multisegment = context.multisegment_cls >>> Point = context.point_cls >>> Polygon = context.polygon_cls >>> Segment = context.segment_cls >>> first_square = Contour([Point(0, 0), Point(4, 0), Point(4, 4), ... Point(0, 4)]) >>> second_square = Contour([Point(4, 0), Point(8, 0), Point(8, 4), ... Point(4, 4)]) >>> third_square = Contour([Point(4, 4), Point(8, 4), Point(8, 8), ... Point(4, 8)]) >>> first_inner_square = Contour([Point(1, 1), Point(3, 1), Point(3, 3), ... Point(1, 3)]) >>> clockwise_first_inner_square = Contour([Point(1, 1), Point(1, 3), ... Point(3, 3), Point(3, 1)]) >>> complete_intersect_polygons(Polygon(first_inner_square, []), ... Polygon(second_square, [])) is EMPTY True >>> (complete_intersect_polygons(Polygon(first_square, []), ... Polygon(third_square, [])) ... == Multipoint([Point(4, 4)])) True >>> (complete_intersect_polygons(Polygon(first_square, []), ... Polygon(second_square, [])) ... == Segment(Point(4, 0), Point(4, 4))) True >>> (complete_intersect_polygons(Polygon(first_inner_square, []), ... Polygon(first_square, ... [clockwise_first_inner_square])) ... == Multisegment([Segment(Point(1, 1), Point(3, 1)), ... Segment(Point(1, 1), Point(1, 3)), ... Segment(Point(1, 3), Point(3, 3)), ... Segment(Point(3, 1), Point(3, 3))])) True >>> (complete_intersect_polygons(Polygon(first_square, []), ... Polygon(first_inner_square, [])) ... == Polygon(first_inner_square, [])) True >>> (complete_intersect_polygons(Polygon(first_square, []), ... Polygon(first_square, [])) ... == Polygon(first_square, [])) True >>> (complete_intersect_polygons(Polygon(first_square, ... [clockwise_first_inner_square]), ... Polygon(first_square, ... [clockwise_first_inner_square])) ... == Polygon(first_square, [clockwise_first_inner_square])) True """ return _holey.CompleteIntersection( _operands.PolygonOperand(first), _operands.PolygonOperand(second), _get_context() if context is None else context ).compute()
[docs]def intersect_polygons(first: _Polygon, second: _Polygon, *, context: _Optional[_Context] = None ) -> _Union[_Empty, _Multipolygon, _Polygon]: """ Returns intersection of polygons. Time complexity: ``O(segments_count * log segments_count)`` Memory complexity: ``O(segments_count)`` where ``segments_count = edges_count + intersections_count``, ``edges_count = first_edges_count + second_edges_count``, ``first_edges_count = len(first.border.vertices)\ + sum(len(hole.vertices) for hole in first.holes)``, ``second_edges_count = len(second.border.vertices)\ + sum(len(hole.vertices) for hole in second.holes)``, ``intersections_count`` --- number of intersections between polygons edges. :param first: first operand. :param second: second operand. :param context: geometric context. :returns: intersection of operands. >>> from ground.base import get_context >>> context = get_context() >>> EMPTY = context.empty >>> Contour = context.contour_cls >>> Point = context.point_cls >>> Polygon = context.polygon_cls >>> first_square = Contour([Point(0, 0), Point(4, 0), Point(4, 4), ... Point(0, 4)]) >>> second_square = Contour([Point(4, 0), Point(8, 0), Point(8, 4), ... Point(4, 4)]) >>> first_inner_square = Contour([Point(1, 1), Point(3, 1), Point(3, 3), ... Point(1, 3)]) >>> clockwise_first_inner_square = Contour([Point(1, 1), Point(1, 3), ... Point(3, 3), Point(3, 1)]) >>> (intersect_polygons(Polygon(first_inner_square, []), ... Polygon(second_square, [])) ... is intersect_polygons(Polygon(first_square, []), ... Polygon(second_square, [])) ... is intersect_polygons(Polygon(first_inner_square, []), ... Polygon(first_square, ... [clockwise_first_inner_square])) ... is EMPTY) True >>> (intersect_polygons(Polygon(first_square, []), ... Polygon(first_inner_square, [])) ... == Polygon(first_inner_square, [])) True >>> (intersect_polygons(Polygon(first_square, ... [clockwise_first_inner_square]), ... Polygon(first_square, ... [clockwise_first_inner_square])) ... == Polygon(first_square, [clockwise_first_inner_square])) True """ return _holey.Intersection( _operands.PolygonOperand(first), _operands.PolygonOperand(second), _get_context() if context is None else context ).compute()
[docs]def subtract_polygons(minuend: _Polygon, subtrahend: _Polygon, *, context: _Optional[_Context] = None ) -> _Union[_Empty, _Multipolygon, _Polygon]: """ Returns difference of polygons. Time complexity: ``O(segments_count * log segments_count)`` Memory complexity: ``O(segments_count)`` where ``segments_count = edges_count + intersections_count``, ``edges_count = minuend_edges_count + subtrahend_edges_count``, ``minuend_edges_count = len(minuend.border.vertices)\ + sum(len(hole.vertices) for hole in minuend.holes)``, ``subtrahend_edges_count = len(subtrahend.border.vertices)\ + sum(len(hole.vertices) for hole in subtrahend.holes)``, ``intersections_count`` --- number of intersections between polygons edges. :param minuend: polygon to subtract from. :param subtrahend: polygon to subtract. :param context: geometric context. :returns: difference between minuend and subtrahend. >>> from ground.base import get_context >>> context = get_context() >>> EMPTY = context.empty >>> Contour = context.contour_cls >>> Multipolygon = context.multipolygon_cls >>> Point = context.point_cls >>> Polygon = context.polygon_cls >>> first_square = Contour([Point(0, 0), Point(4, 0), Point(4, 4), ... Point(0, 4)]) >>> second_square = Contour([Point(4, 0), Point(8, 0), Point(8, 4), ... Point(4, 4)]) >>> first_inner_square = Contour([Point(1, 1), Point(3, 1), Point(3, 3), ... Point(1, 3)]) >>> clockwise_first_inner_square = Contour([Point(1, 1), Point(1, 3), ... Point(3, 3), Point(3, 1)]) >>> (subtract_polygons(Polygon(first_square, []), ... Polygon(first_square, [])) ... is subtract_polygons(Polygon(first_inner_square, []), ... Polygon(first_square, [])) ... is subtract_polygons(Polygon(first_square, ... [clockwise_first_inner_square]), ... Polygon(first_square, ... [clockwise_first_inner_square])) ... is EMPTY) True >>> (subtract_polygons(Polygon(first_inner_square, []), ... Polygon(second_square, [])) ... == subtract_polygons(Polygon(first_inner_square, []), ... Polygon(first_square, ... [clockwise_first_inner_square])) ... == Polygon(first_inner_square, [])) True >>> (subtract_polygons(Polygon(first_square, []), ... Polygon(first_inner_square, [])) ... == subtract_polygons(Polygon(first_square, [first_inner_square]), ... Polygon(second_square, [])) ... == Polygon(first_square, [clockwise_first_inner_square])) True """ return _holey.Difference( _operands.PolygonOperand(minuend), _operands.PolygonOperand(subtrahend), _get_context() if context is None else context ).compute()
[docs]def symmetric_subtract_polygons(first: _Polygon, second: _Polygon, *, context: _Optional[_Context] = None ) -> _Union[_Empty, _Multipolygon, _Polygon]: """ Returns symmetric difference of polygons. Time complexity: ``O(segments_count * log segments_count)`` Memory complexity: ``O(segments_count)`` where ``segments_count = edges_count + intersections_count``, ``edges_count = first_edges_count + second_edges_count``, ``first_edges_count = len(first.border.vertices)\ + sum(len(hole.vertices) for hole in first.holes)``, ``second_edges_count = len(second.border.vertices)\ + sum(len(hole.vertices) for hole in second.holes)``, ``intersections_count`` --- number of intersections between polygons edges. :param first: first operand. :param second: second operand. :param context: geometric context. :returns: symmetric difference of operands. >>> from ground.base import get_context >>> context = get_context() >>> EMPTY = context.empty >>> Contour = context.contour_cls >>> Multipolygon = context.multipolygon_cls >>> Point = context.point_cls >>> Polygon = context.polygon_cls >>> first_square = Contour([Point(0, 0), Point(4, 0), Point(4, 4), ... Point(0, 4)]) >>> second_square = Contour([Point(4, 0), Point(8, 0), Point(8, 4), ... Point(4, 4)]) >>> third_square = Contour([Point(4, 4), Point(8, 4), Point(8, 8), ... Point(4, 8)]) >>> first_inner_square = Contour([Point(1, 1), Point(3, 1), Point(3, 3), ... Point(1, 3)]) >>> clockwise_first_inner_square = Contour([Point(1, 1), Point(1, 3), ... Point(3, 3), Point(3, 1)]) >>> (symmetric_subtract_polygons(Polygon(first_square, []), ... Polygon(first_square, [])) ... is symmetric_subtract_polygons( ... Polygon(first_square, [clockwise_first_inner_square]), ... Polygon(first_square, [clockwise_first_inner_square])) ... is EMPTY) True >>> (symmetric_subtract_polygons(Polygon(first_square, ... [clockwise_first_inner_square]), ... Polygon(first_inner_square, [])) ... == Polygon(first_square, [])) True >>> (symmetric_subtract_polygons(Polygon(first_square, []), ... Polygon(second_square, [])) ... == Polygon(Contour([Point(0, 0), Point(8, 0), Point(8, 4), ... Point(0, 4)]), [])) True >>> (symmetric_subtract_polygons( ... Polygon(first_square, [clockwise_first_inner_square]), ... Polygon(second_square, [])) ... == Polygon(Contour([Point(0, 0), Point(8, 0), Point(8, 4), ... Point(0, 4)]), [clockwise_first_inner_square])) True >>> (symmetric_subtract_polygons(Polygon(first_square, []), ... Polygon(third_square, [])) ... == Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])])) True >>> (symmetric_subtract_polygons(Polygon(first_square, ... [clockwise_first_inner_square]), ... Polygon(third_square, [])) ... == Multipolygon([Polygon(first_square, ... [clockwise_first_inner_square]), ... Polygon(third_square, [])])) True """ return _holey.SymmetricDifference( _operands.PolygonOperand(first), _operands.PolygonOperand(second), _get_context() if context is None else context ).compute()
[docs]def unite_polygons(first: _Polygon, second: _Polygon, *, context: _Optional[_Context] = None ) -> _Union[_Multipolygon, _Polygon]: """ Returns union of polygons. Time complexity: ``O(segments_count * log segments_count)`` Memory complexity: ``O(segments_count)`` where ``segments_count = edges_count + intersections_count``, ``edges_count = first_edges_count + second_edges_count``, ``first_edges_count = len(first.border.vertices)\ + sum(len(hole.vertices) for hole in first.holes)``, ``second_edges_count = len(second.border.vertices)\ + sum(len(hole.vertices) for hole in second.holes)``, ``intersections_count`` --- number of intersections between polygons edges. :param first: first operand. :param second: second operand. :param context: geometric context. :returns: union of operands. >>> from ground.base import get_context >>> context = get_context() >>> EMPTY = context.empty >>> Contour = context.contour_cls >>> Multipolygon = context.multipolygon_cls >>> Point = context.point_cls >>> Polygon = context.polygon_cls >>> first_square = Contour([Point(0, 0), Point(4, 0), Point(4, 4), ... Point(0, 4)]) >>> second_square = Contour([Point(4, 0), Point(8, 0), Point(8, 4), ... Point(4, 4)]) >>> third_square = Contour([Point(4, 4), Point(8, 4), Point(8, 8), ... Point(4, 8)]) >>> fourth_square = Contour([Point(0, 4), Point(4, 4), Point(4, 8), ... Point(0, 8)]) >>> first_inner_square = Contour([Point(1, 1), Point(3, 1), Point(3, 3), ... Point(1, 3)]) >>> second_inner_square = Contour([Point(5, 1), Point(7, 1), Point(7, 3), ... Point(5, 3)]) >>> third_inner_square = Contour([Point(5, 5), Point(7, 5), Point(7, 7), ... Point(5, 7)]) >>> clockwise_first_inner_square = Contour([Point(1, 1), Point(1, 3), ... Point(3, 3), Point(3, 1)]) >>> clockwise_second_inner_square = Contour([Point(5, 1), Point(7, 1), ... Point(7, 3), Point(5, 3)]) >>> clockwise_third_inner_square = Contour([Point(5, 5), Point(5, 7), ... Point(7, 7), Point(7, 5)]) >>> (unite_polygons(Polygon(first_square, []), ... Polygon(first_inner_square, [])) ... == unite_polygons(Polygon(first_square, ... [clockwise_first_inner_square]), ... Polygon(first_inner_square, [])) ... == Polygon(first_square, [])) True >>> (unite_polygons(Polygon(first_square, []), ... Polygon(second_square, [])) ... == Polygon(Contour([Point(0, 0), Point(8, 0), Point(8, 4), ... Point(0, 4)]), [])) True >>> (unite_polygons(Polygon(first_square, [clockwise_first_inner_square]), ... Polygon(second_square, [])) ... == Polygon(Contour([Point(0, 0), Point(8, 0), Point(8, 4), ... Point(0, 4)]), [clockwise_first_inner_square])) True >>> (unite_polygons(Polygon(first_square, []), ... Polygon(third_square, [])) ... == Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])])) True >>> (unite_polygons(Polygon(first_square, [clockwise_first_inner_square]), ... Polygon(third_square, [])) ... == Multipolygon([Polygon(first_square, ... [clockwise_first_inner_square]), ... Polygon(third_square, [])])) True """ return _holey.Union( _operands.PolygonOperand(first), _operands.PolygonOperand(second), _get_context() if context is None else context ).compute()
[docs]def complete_intersect_polygon_with_multipolygon( polygon: _Polygon, multipolygon: _Multipolygon, *, context: _Optional[_Context] = None ) -> _Union[_Empty, _Mix, _Multipoint, _Multipolygon, _Multisegment, _Polygon, _Segment]: """ Returns intersection of polygon with multipolygon considering cases with polygons touching each other in points/segments. Time complexity: ``O(segments_count * log segments_count)`` Memory complexity: ``O(segments_count)`` where ``segments_count = edges_count + intersections_count``, ``edges_count = polygon_edges_count + multipolygon_edges_count``, ``polygon_edges_count = len(polygon.border.vertices)\ + sum(len(hole.vertices) for hole in polygon.holes)``, ``multipolygon_edges_count = sum(len(polygon.border.vertices)\ + sum(len(hole.vertices) for hole in polygon.holes)\ for polygon in multipolygon.polygons)``, ``intersections_count`` --- number of intersections between polygons edges. :param polygon: first operand. :param multipolygon: second operand. :param context: geometric context. :returns: intersection of operands. >>> from ground.base import get_context >>> context = get_context() >>> EMPTY = context.empty >>> Contour = context.contour_cls >>> Mix = context.mix_cls >>> Multipoint = context.multipoint_cls >>> Multipolygon = context.multipolygon_cls >>> Multisegment = context.multisegment_cls >>> Point = context.point_cls >>> Polygon = context.polygon_cls >>> Segment = context.segment_cls >>> first_square = Contour([Point(0, 0), Point(4, 0), Point(4, 4), ... Point(0, 4)]) >>> second_square = Contour([Point(4, 0), Point(8, 0), Point(8, 4), ... Point(4, 4)]) >>> third_square = Contour([Point(4, 4), Point(8, 4), Point(8, 8), ... Point(4, 8)]) >>> fourth_square = Contour([Point(0, 4), Point(4, 4), Point(4, 8), ... Point(0, 8)]) >>> first_inner_square = Contour([Point(1, 1), Point(3, 1), Point(3, 3), ... Point(1, 3)]) >>> second_inner_square = Contour([Point(5, 1), Point(7, 1), Point(7, 3), ... Point(5, 3)]) >>> third_inner_square = Contour([Point(5, 5), Point(7, 5), Point(7, 7), ... Point(5, 7)]) >>> clockwise_first_inner_square = Contour([Point(1, 1), Point(1, 3), ... Point(3, 3), Point(3, 1)]) >>> clockwise_second_inner_square = Contour([Point(5, 1), Point(5, 3), ... Point(7, 3), Point(7, 1)]) >>> clockwise_third_inner_square = Contour([Point(5, 5), Point(5, 7), ... Point(7, 7), Point(7, 5)]) >>> (complete_intersect_polygon_with_multipolygon( ... Polygon(first_inner_square, []), ... Multipolygon([Polygon(second_square, []), ... Polygon(fourth_square, [])])) ... is EMPTY) True >>> (complete_intersect_polygon_with_multipolygon( ... Polygon(first_square, []), ... Multipolygon([Polygon(second_inner_square, []), ... Polygon(third_square, [])])) ... == Multipoint([Point(4, 4)])) True >>> (complete_intersect_polygon_with_multipolygon( ... Polygon(first_square, []), ... Multipolygon([Polygon(second_square, []), ... Polygon(fourth_square, [])])) ... == Multisegment([Segment(Point(0, 4), Point(4, 4)), ... Segment(Point(4, 0), Point(4, 4))])) True >>> (complete_intersect_polygon_with_multipolygon( ... Polygon(first_inner_square, []), ... Multipolygon([Polygon(first_square, ... [clockwise_first_inner_square]), ... Polygon(third_square, ... [clockwise_third_inner_square])])) ... == Multisegment([Segment(Point(1, 1), Point(3, 1)), ... Segment(Point(1, 1), Point(1, 3)), ... Segment(Point(1, 3), Point(3, 3)), ... Segment(Point(3, 1), Point(3, 3))])) True >>> (complete_intersect_polygon_with_multipolygon( ... Polygon(first_square, []), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_inner_square, [])])) ... == complete_intersect_polygon_with_multipolygon( ... Polygon(first_inner_square, []), ... Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])])) ... == complete_intersect_polygon_with_multipolygon( ... Polygon(first_square, []), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_inner_square, [])])) ... == complete_intersect_polygon_with_multipolygon( ... Polygon(first_inner_square, []), ... Multipolygon([Polygon(first_square, []), ... Polygon(third_inner_square, [])])) ... == complete_intersect_polygon_with_multipolygon( ... Polygon(first_inner_square, []), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_inner_square, [])])) ... == complete_intersect_polygon_with_multipolygon( ... Polygon(first_inner_square, []), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_inner_square, []), ... Polygon(third_inner_square, [])])) ... == Polygon(first_inner_square, [])) True >>> (complete_intersect_polygon_with_multipolygon( ... Polygon(first_square, []), ... Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])])) ... == Polygon(first_square, [])) True >>> (complete_intersect_polygon_with_multipolygon( ... Polygon(first_square, []), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_square, [])])) ... == Mix(Multipoint([Point(4, 4)]), EMPTY, ... Polygon(first_inner_square, []))) True >>> (complete_intersect_polygon_with_multipolygon( ... Polygon(first_square, []), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_square, [])])) ... == Mix(EMPTY, Segment(Point(4, 0), Point(4, 4)), ... Polygon(first_inner_square, []))) True """ return _holey.CompleteIntersection( _operands.PolygonOperand(polygon), _operands.MultipolygonOperand(multipolygon), _get_context() if context is None else context ).compute()
[docs]def intersect_polygon_with_multipolygon(polygon: _Polygon, multipolygon: _Multipolygon, *, context: _Optional[_Context] = None ) -> _Union[_Empty, _Multipolygon, _Polygon]: """ Returns intersection of multipolygons. Time complexity: ``O(segments_count * log segments_count)`` Memory complexity: ``O(segments_count)`` where ``segments_count = edges_count + intersections_count``, ``edges_count = polygon_edges_count + multipolygon_edges_count``, ``polygon_edges_count = len(polygon.border.vertices)\ + sum(len(hole.vertices) for hole in polygon.holes)``, ``multipolygon_edges_count = sum(len(polygon.border.vertices)\ + sum(len(hole.vertices) for hole in polygon.holes)\ for polygon in multipolygon.polygons)``, ``intersections_count`` --- number of intersections between polygons edges. :param polygon: first operand. :param multipolygon: second operand. :param context: geometric context. :returns: intersection of operands. >>> from ground.base import get_context >>> context = get_context() >>> EMPTY = context.empty >>> Contour = context.contour_cls >>> Multipolygon = context.multipolygon_cls >>> Point = context.point_cls >>> Polygon = context.polygon_cls >>> first_square = Contour([Point(0, 0), Point(4, 0), Point(4, 4), ... Point(0, 4)]) >>> second_square = Contour([Point(4, 0), Point(8, 0), Point(8, 4), ... Point(4, 4)]) >>> third_square = Contour([Point(4, 4), Point(8, 4), Point(8, 8), ... Point(4, 8)]) >>> fourth_square = Contour([Point(0, 4), Point(4, 4), Point(4, 8), ... Point(0, 8)]) >>> first_inner_square = Contour([Point(1, 1), Point(3, 1), Point(3, 3), ... Point(1, 3)]) >>> second_inner_square = Contour([Point(5, 1), Point(7, 1), Point(7, 3), ... Point(5, 3)]) >>> third_inner_square = Contour([Point(5, 5), Point(7, 5), Point(7, 7), ... Point(5, 7)]) >>> clockwise_first_inner_square = Contour([Point(1, 1), Point(1, 3), ... Point(3, 3), Point(3, 1)]) >>> clockwise_second_inner_square = Contour([Point(5, 1), Point(5, 3), ... Point(7, 3), Point(7, 1)]) >>> clockwise_third_inner_square = Contour([Point(5, 5), Point(5, 7), ... Point(7, 7), Point(7, 5)]) >>> (intersect_polygon_with_multipolygon( ... Polygon(first_inner_square, []), ... Multipolygon([Polygon(second_square, []), ... Polygon(fourth_square, [])])) ... is intersect_polygon_with_multipolygon( ... Polygon(first_square, []), ... Multipolygon([Polygon(second_square, []), ... Polygon(fourth_square, [])])) ... is intersect_polygon_with_multipolygon( ... Polygon(first_inner_square, []), ... Multipolygon([Polygon(first_square, ... [clockwise_first_inner_square]), ... Polygon(third_square, ... [clockwise_third_inner_square])])) ... is EMPTY) True >>> (intersect_polygon_with_multipolygon( ... Polygon(first_square, []), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_square, [])])) ... == Polygon(first_inner_square, [])) True >>> (intersect_polygon_with_multipolygon( ... Polygon(first_square, []), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_square, [])])) ... == intersect_polygon_with_multipolygon( ... Polygon(first_square, []), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_inner_square, [])])) ... == intersect_polygon_with_multipolygon( ... Polygon(first_inner_square, []), ... Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])])) ... == intersect_polygon_with_multipolygon( ... Polygon(first_square, []), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_inner_square, [])])) ... == intersect_polygon_with_multipolygon( ... Polygon(first_inner_square, []), ... Multipolygon([Polygon(first_square, []), ... Polygon(third_inner_square, [])])) ... == intersect_polygon_with_multipolygon( ... Polygon(first_inner_square, []), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_inner_square, [])])) ... == intersect_polygon_with_multipolygon( ... Polygon(first_inner_square, []), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_inner_square, []), ... Polygon(third_inner_square, [])])) ... == Polygon(first_inner_square, [])) True >>> (intersect_polygon_with_multipolygon( ... Polygon(first_square, []), ... Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])])) ... == Polygon(first_square, [])) True """ return _holey.Intersection( _operands.PolygonOperand(polygon), _operands.MultipolygonOperand(multipolygon), _get_context() if context is None else context ).compute()
[docs]def subtract_multipolygon_from_polygon(minuend: _Polygon, subtrahend: _Multipolygon, *, context: _Optional[_Context] = None ) -> _Union[_Empty, _Multipolygon, _Polygon]: """ Returns difference of polygon with multipolygon. Time complexity: ``O(segments_count * log segments_count)`` Memory complexity: ``O(segments_count)`` where ``segments_count = edges_count + intersections_count``, ``edges_count = first_edges_count + second_edges_count``, ``first_edges_count = len(minuend.border.vertices)\ + sum(len(hole.vertices) for hole in minuend.holes)``, ``second_edges_count = sum(len(polygon.border.vertices)\ + sum(len(hole.vertices) for hole in polygon.holes)\ for polygon in subtrahend.polygons)``, ``intersections_count`` --- number of intersections between polygons edges. :param minuend: polygon to subtract from. :param subtrahend: multipolygon to subtract. :param context: geometric context. :returns: difference between minuend and subtrahend. >>> from ground.base import get_context >>> context = get_context() >>> EMPTY = context.empty >>> Contour = context.contour_cls >>> Multipolygon = context.multipolygon_cls >>> Point = context.point_cls >>> Polygon = context.polygon_cls >>> first_square = Contour([Point(0, 0), Point(4, 0), Point(4, 4), ... Point(0, 4)]) >>> second_square = Contour([Point(4, 0), Point(8, 0), Point(8, 4), ... Point(4, 4)]) >>> third_square = Contour([Point(4, 4), Point(8, 4), Point(8, 8), ... Point(4, 8)]) >>> fourth_square = Contour([Point(0, 4), Point(4, 4), Point(4, 8), ... Point(0, 8)]) >>> outer_square = Contour([Point(0, 0), Point(8, 0), Point(8, 8), ... Point(0, 8)]) >>> first_inner_square = Contour([Point(1, 1), Point(3, 1), Point(3, 3), ... Point(1, 3)]) >>> second_inner_square = Contour([Point(5, 1), Point(7, 1), Point(7, 3), ... Point(5, 3)]) >>> third_inner_square = Contour([Point(5, 5), Point(7, 5), Point(7, 7), ... Point(5, 7)]) >>> clockwise_first_inner_square = Contour([Point(1, 1), Point(1, 3), ... Point(3, 3), Point(3, 1)]) >>> clockwise_second_inner_square = Contour([Point(5, 1), Point(5, 3), ... Point(7, 3), Point(7, 1)]) >>> clockwise_third_inner_square = Contour([Point(5, 5), Point(5, 7), ... Point(7, 7), Point(7, 5)]) >>> (subtract_multipolygon_from_polygon( ... Polygon(first_square, []), ... Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])])) ... is subtract_multipolygon_from_polygon( ... Polygon(first_inner_square, []), ... Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])])) ... is subtract_multipolygon_from_polygon( ... Polygon(first_inner_square, []), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_inner_square, []), ... Polygon(third_inner_square, [])])) ... is EMPTY) True >>> (subtract_multipolygon_from_polygon( ... Polygon(first_inner_square, []), ... Multipolygon([Polygon(second_inner_square, []), ... Polygon(third_inner_square, [])])) ... == subtract_multipolygon_from_polygon( ... Polygon(first_inner_square, []), ... Multipolygon([Polygon(first_square, ... [clockwise_first_inner_square]), ... Polygon(third_square, ... [clockwise_third_inner_square])])) ... == Polygon(first_inner_square, [])) True >>> (subtract_multipolygon_from_polygon( ... Polygon(first_square, []), ... Multipolygon([Polygon(second_square, []), ... Polygon(fourth_square, [])])) ... == Polygon(first_square, [])) True >>> (subtract_multipolygon_from_polygon( ... Polygon(first_square, []), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_square, [])])) ... == Polygon(first_square, [clockwise_first_inner_square])) True >>> (subtract_multipolygon_from_polygon( ... Polygon(outer_square, []), ... Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])])) ... == Multipolygon([Polygon(fourth_square, []), ... Polygon(second_square, [])])) True >>> (subtract_multipolygon_from_polygon( ... Polygon(outer_square, []), ... Multipolygon([Polygon(first_square, ... [clockwise_first_inner_square]), ... Polygon(third_square, ... [clockwise_third_inner_square])])) ... == Multipolygon([Polygon(fourth_square, []), ... Polygon(first_inner_square, []), ... Polygon(second_square, []), ... Polygon(third_inner_square, [])])) True >>> (subtract_multipolygon_from_polygon( ... Polygon(outer_square, []), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_square, []), ... Polygon(third_inner_square, []), ... Polygon(fourth_square, [])])) ... == Multipolygon([Polygon(first_square, ... [clockwise_first_inner_square]), ... Polygon(third_square, ... [clockwise_third_inner_square])])) True """ return _holey.Difference( _operands.PolygonOperand(minuend), _operands.MultipolygonOperand(subtrahend), _get_context() if context is None else context ).compute()
[docs]def subtract_polygon_from_multipolygon(minuend: _Multipolygon, subtrahend: _Polygon, *, context: _Optional[_Context] = None ) -> _Union[_Empty, _Multipolygon, _Polygon]: """ Returns difference of multipolygon with polygon. Time complexity: ``O(segments_count * log segments_count)`` Memory complexity: ``O(segments_count)`` where ``segments_count = edges_count + intersections_count``, ``edges_count = minuend_edges_count + subtrahend_edges_count``, ``minuend_edges_count = sum(len(polygon.border.vertices)\ + sum(len(hole.vertices) for hole in polygon.holes)\ for polygon in minuend.polygons)``, ``subtrahend_edges_count = len(subtrahend.border.vertices)\ + sum(len(hole.vertices) for hole in subtrahend.holes)``, ``intersections_count`` --- number of intersections between polygons edges. :param minuend: multipolygon to subtract from. :param subtrahend: polygon to subtract. :param context: geometric context. :returns: difference between minuend and subtrahend. >>> from ground.base import get_context >>> context = get_context() >>> EMPTY = context.empty >>> Contour = context.contour_cls >>> Multipolygon = context.multipolygon_cls >>> Point = context.point_cls >>> Polygon = context.polygon_cls >>> first_square = Contour([Point(0, 0), Point(4, 0), Point(4, 4), ... Point(0, 4)]) >>> second_square = Contour([Point(4, 0), Point(8, 0), Point(8, 4), ... Point(4, 4)]) >>> third_square = Contour([Point(4, 4), Point(8, 4), Point(8, 8), ... Point(4, 8)]) >>> fourth_square = Contour([Point(0, 4), Point(4, 4), Point(4, 8), ... Point(0, 8)]) >>> outer_square = Contour([Point(0, 0), Point(8, 0), Point(8, 8), ... Point(0, 8)]) >>> first_inner_square = Contour([Point(1, 1), Point(3, 1), Point(3, 3), ... Point(1, 3)]) >>> second_inner_square = Contour([Point(5, 1), Point(7, 1), Point(7, 3), ... Point(5, 3)]) >>> third_inner_square = Contour([Point(5, 5), Point(7, 5), Point(7, 7), ... Point(5, 7)]) >>> clockwise_first_inner_square = Contour([Point(1, 1), Point(1, 3), ... Point(3, 3), Point(3, 1)]) >>> clockwise_second_inner_square = Contour([Point(5, 1), Point(5, 3), ... Point(7, 3), Point(7, 1)]) >>> clockwise_third_inner_square = Contour([Point(5, 5), Point(5, 7), ... Point(7, 7), Point(7, 5)]) >>> (subtract_polygon_from_multipolygon( ... Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])]), ... Polygon(outer_square, [])) ... is subtract_polygon_from_multipolygon( ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_inner_square, []), ... Polygon(third_inner_square, [])]), ... Polygon(outer_square, [])) ... is EMPTY) True >>> (subtract_polygon_from_multipolygon( ... Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])]), ... Polygon(third_square, [])) ... == Polygon(first_square, [])) True >>> (subtract_polygon_from_multipolygon( ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_inner_square, [])]), ... Polygon(third_inner_square, [])) ... == subtract_polygon_from_multipolygon( ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_inner_square, []), ... Polygon(third_inner_square, [])]), ... Polygon(third_inner_square, [])) ... == subtract_polygon_from_multipolygon( ... Multipolygon([Polygon(first_square, []), ... Polygon(second_inner_square, [])]), ... Polygon(first_square, [clockwise_first_inner_square])) ... == Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_inner_square, [])])) True >>> (subtract_polygon_from_multipolygon( ... Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])]), ... Polygon(second_square, [])) ... == Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])])) True >>> (subtract_polygon_from_multipolygon( ... Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])]), ... Polygon(first_inner_square, [])) ... == subtract_polygon_from_multipolygon( ... Multipolygon([Polygon(first_square, ... [clockwise_first_inner_square]), ... Polygon(third_square, [])]), ... Polygon(first_inner_square, [])) ... == Multipolygon([Polygon(first_square, ... [clockwise_first_inner_square]), ... Polygon(third_square, [])])) True """ return _holey.Difference( _operands.MultipolygonOperand(minuend), _operands.PolygonOperand(subtrahend), _get_context() if context is None else context ).compute()
[docs]def symmetric_subtract_multipolygon_from_polygon( polygon: _Polygon, multipolygon: _Multipolygon, *, context: _Optional[_Context] = None ) -> _Union[_Multipolygon, _Polygon]: """ Returns symmetric difference of polygon with multipolygon. Time complexity: ``O(segments_count * log segments_count)`` Memory complexity: ``O(segments_count)`` where ``segments_count = edges_count + intersections_count``, ``edges_count = polygon_edges_count + multipolygon_edges_count``, ``polygon_edges_count = len(polygon.border.vertices)\ + sum(len(hole.vertices) for hole in polygon.holes)``, ``multipolygon_edges_count = sum(len(polygon.border.vertices)\ + sum(len(hole.vertices) for hole in polygon.holes)\ for polygon in multipolygon.polygons)``, ``intersections_count`` --- number of intersections between polygons edges. :param polygon: first operand. :param multipolygon: second operand. :param context: geometric context. :returns: symmetric difference of operands. >>> from ground.base import get_context >>> context = get_context() >>> EMPTY = context.empty >>> Contour = context.contour_cls >>> Multipolygon = context.multipolygon_cls >>> Point = context.point_cls >>> Polygon = context.polygon_cls >>> first_square = Contour([Point(0, 0), Point(4, 0), Point(4, 4), ... Point(0, 4)]) >>> second_square = Contour([Point(4, 0), Point(8, 0), Point(8, 4), ... Point(4, 4)]) >>> third_square = Contour([Point(4, 4), Point(8, 4), Point(8, 8), ... Point(4, 8)]) >>> fourth_square = Contour([Point(0, 4), Point(4, 4), Point(4, 8), ... Point(0, 8)]) >>> outer_square = Contour([Point(0, 0), Point(8, 0), Point(8, 8), ... Point(0, 8)]) >>> first_inner_square = Contour([Point(1, 1), Point(3, 1), Point(3, 3), ... Point(1, 3)]) >>> second_inner_square = Contour([Point(5, 1), Point(7, 1), Point(7, 3), ... Point(5, 3)]) >>> third_inner_square = Contour([Point(5, 5), Point(7, 5), Point(7, 7), ... Point(5, 7)]) >>> clockwise_first_inner_square = Contour([Point(1, 1), Point(1, 3), ... Point(3, 3), Point(3, 1)]) >>> clockwise_second_inner_square = Contour([Point(5, 1), Point(5, 3), ... Point(7, 3), Point(7, 1)]) >>> clockwise_third_inner_square = Contour([Point(5, 5), Point(5, 7), ... Point(7, 7), Point(7, 5)]) >>> (symmetric_subtract_multipolygon_from_polygon( ... Polygon(first_square, []), ... Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])])) ... == Polygon(third_square, [])) True >>> (symmetric_subtract_multipolygon_from_polygon( ... Polygon(first_square, []), ... Multipolygon([Polygon(second_square, []), ... Polygon(fourth_square, [])])) ... == Polygon(Contour([Point(0, 0), Point(8, 0), Point(8, 4), ... Point(4, 4), Point(4, 8), Point(0, 8)]), [])) True >>> (symmetric_subtract_multipolygon_from_polygon( ... Polygon(outer_square, []), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_inner_square, []), ... Polygon(third_inner_square, [])])) ... == Polygon(outer_square, [clockwise_first_inner_square, ... clockwise_second_inner_square, ... clockwise_third_inner_square])) True >>> (symmetric_subtract_multipolygon_from_polygon( ... Polygon(first_inner_square, []), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_inner_square, []), ... Polygon(third_inner_square, [])])) ... == Multipolygon([Polygon(second_inner_square, []), ... Polygon(third_inner_square, [])])) True >>> (symmetric_subtract_multipolygon_from_polygon( ... Polygon(first_inner_square, []), ... Multipolygon([Polygon(first_square, ... [clockwise_first_inner_square]), ... Polygon(third_square, [])])) ... == symmetric_subtract_multipolygon_from_polygon( ... Polygon(outer_square, []), ... Multipolygon([Polygon(second_square, []), ... Polygon(fourth_square, [])])) ... == Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])])) True >>> (symmetric_subtract_multipolygon_from_polygon( ... Polygon(first_inner_square, []), ... Multipolygon([Polygon(second_inner_square, []), ... Polygon(third_inner_square, [])])) ... == Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_inner_square, []), ... Polygon(third_inner_square, [])])) True >>> (symmetric_subtract_multipolygon_from_polygon( ... Polygon(outer_square, []), ... Multipolygon([Polygon(first_square, ... [clockwise_first_inner_square]), ... Polygon(third_square, ... [clockwise_third_inner_square])])) ... == symmetric_subtract_multipolygon_from_polygon( ... Polygon(outer_square, [clockwise_first_inner_square, ... clockwise_third_inner_square]), ... Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])])) ... == Multipolygon([Polygon(fourth_square, []), ... Polygon(first_inner_square, []), ... Polygon(second_square, []), ... Polygon(third_inner_square, [])])) True >>> (symmetric_subtract_multipolygon_from_polygon( ... Polygon(first_square, []), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_inner_square, [])])) ... == symmetric_subtract_multipolygon_from_polygon( ... Polygon(first_inner_square, []), ... Multipolygon([Polygon(first_square, []), ... Polygon(third_inner_square, [])])) ... == Multipolygon([Polygon(first_square, ... [clockwise_first_inner_square]), ... Polygon(third_inner_square, [])])) True >>> (symmetric_subtract_multipolygon_from_polygon( ... Polygon(outer_square, []), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_square, []), ... Polygon(third_inner_square, []), ... Polygon(fourth_square, [])])) ... == Multipolygon([Polygon(first_square, ... [clockwise_first_inner_square]), ... Polygon(third_square, ... [clockwise_third_inner_square])])) True """ return _holey.SymmetricDifference( _operands.PolygonOperand(polygon), _operands.MultipolygonOperand(multipolygon), _get_context() if context is None else context).compute()
[docs]def unite_polygon_with_multipolygon(polygon: _Polygon, multipolygon: _Multipolygon, *, context: _Optional[_Context] = None ) -> _Union[_Multipolygon, _Polygon]: """ Returns union of polygon with multipolygon. Time complexity: ``O(segments_count * log segments_count)`` Memory complexity: ``O(segments_count)`` where ``segments_count = edges_count + intersections_count``, ``edges_count = polygon_edges_count + multipolygon_edges_count``, ``polygon_edges_count = len(polygon.border.vertices)\ + sum(len(hole.vertices) for hole in polygon.holes)``, ``multipolygon_edges_count = sum(len(polygon.border.vertices)\ + sum(len(hole.vertices) for hole in polygon.holes)\ for polygon in multipolygon.polygons)``, ``intersections_count`` --- number of intersections between polygons edges. :param polygon: first operand. :param multipolygon: second operand. :param context: geometric context. :returns: union of operands. >>> from ground.base import get_context >>> context = get_context() >>> EMPTY = context.empty >>> Contour = context.contour_cls >>> Multipolygon = context.multipolygon_cls >>> Point = context.point_cls >>> Polygon = context.polygon_cls >>> first_square = Contour([Point(0, 0), Point(4, 0), Point(4, 4), ... Point(0, 4)]) >>> second_square = Contour([Point(4, 0), Point(8, 0), Point(8, 4), ... Point(4, 4)]) >>> third_square = Contour([Point(4, 4), Point(8, 4), Point(8, 8), ... Point(4, 8)]) >>> fourth_square = Contour([Point(0, 4), Point(4, 4), Point(4, 8), ... Point(0, 8)]) >>> outer_square = Contour([Point(0, 0), Point(8, 0), Point(8, 8), ... Point(0, 8)]) >>> first_inner_square = Contour([Point(1, 1), Point(3, 1), Point(3, 3), ... Point(1, 3)]) >>> second_inner_square = Contour([Point(5, 1), Point(7, 1), Point(7, 3), ... Point(5, 3)]) >>> third_inner_square = Contour([Point(5, 5), Point(7, 5), Point(7, 7), ... Point(5, 7)]) >>> clockwise_first_inner_square = Contour([Point(1, 1), Point(1, 3), ... Point(3, 3), Point(3, 1)]) >>> clockwise_second_inner_square = Contour([Point(5, 1), Point(7, 1), ... Point(7, 3), Point(5, 3)]) >>> clockwise_third_inner_square = Contour([Point(5, 5), Point(5, 7), ... Point(7, 7), Point(7, 5)]) >>> (unite_polygon_with_multipolygon( ... Polygon(first_square, []), ... Multipolygon([Polygon(second_square, []), ... Polygon(fourth_square, [])])) ... == Polygon(Contour([Point(0, 0), Point(8, 0), Point(8, 4), ... Point(4, 4), Point(4, 8), Point(0, 8)]), [])) True >>> (unite_polygon_with_multipolygon( ... Polygon(outer_square, []), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_inner_square, []), ... Polygon(third_inner_square, [])])) ... == unite_polygon_with_multipolygon( ... Polygon(outer_square, []), ... Multipolygon([Polygon(first_square, ... [clockwise_first_inner_square]), ... Polygon(third_square, ... [clockwise_third_inner_square])])) ... == Polygon(outer_square, [])) True >>> (unite_polygon_with_multipolygon( ... Polygon(first_inner_square, []), ... Multipolygon([Polygon(first_square, ... [clockwise_first_inner_square]), ... Polygon(third_square, [])])) ... == Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])])) True >>> (unite_polygon_with_multipolygon( ... Polygon(first_inner_square, []), ... Multipolygon([Polygon(second_inner_square, []), ... Polygon(third_inner_square, [])])) ... == unite_polygon_with_multipolygon( ... Polygon(first_inner_square, []), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_inner_square, []), ... Polygon(third_inner_square, [])])) ... == Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_inner_square, []), ... Polygon(third_inner_square, [])])) True >>> (unite_polygon_with_multipolygon( ... Polygon(first_square, [clockwise_first_inner_square]), ... Multipolygon([Polygon(first_square, ... [clockwise_first_inner_square]), ... Polygon(third_square, ... [clockwise_third_inner_square])])) ... == Multipolygon([Polygon(first_square, ... [clockwise_first_inner_square]), ... Polygon(third_square, ... [clockwise_third_inner_square])])) True """ return _holey.Union( _operands.PolygonOperand(polygon), _operands.MultipolygonOperand(multipolygon), _get_context() if context is None else context ).compute()
[docs]def complete_intersect_multipolygons( first: _Multipolygon, second: _Multipolygon, *, context: _Optional[_Context] = None ) -> _Union[_Empty, _Mix, _Multipoint, _Multipolygon, _Multisegment, _Polygon, _Segment]: """ Returns intersection of multipolygons considering cases with polygons touching each other in points/segments. Time complexity: ``O(segments_count * log segments_count)`` Memory complexity: ``O(segments_count)`` where ``segments_count = edges_count + intersections_count``, ``edges_count = first_edges_count + second_edges_count``, ``first_edges_count = sum(len(polygon.border.vertices)\ + sum(len(hole.vertices) for hole in polygon.holes)\ for polygon in first.polygons)``, ``second_edges_count = sum(len(polygon.border.vertices)\ + sum(len(hole.vertices) for hole in polygon.holes)\ for polygon in second.polygons)``, ``intersections_count`` --- number of intersections between multipolygons edges. :param first: first operand. :param second: second operand. :param context: geometric context. :returns: intersection of operands. >>> from ground.base import get_context >>> context = get_context() >>> EMPTY = context.empty >>> Contour = context.contour_cls >>> Mix = context.mix_cls >>> Multipoint = context.multipoint_cls >>> Multipolygon = context.multipolygon_cls >>> Multisegment = context.multisegment_cls >>> Point = context.point_cls >>> Polygon = context.polygon_cls >>> Segment = context.segment_cls >>> first_square = Contour([Point(0, 0), Point(4, 0), Point(4, 4), ... Point(0, 4)]) >>> second_square = Contour([Point(4, 0), Point(8, 0), Point(8, 4), ... Point(4, 4)]) >>> third_square = Contour([Point(4, 4), Point(8, 4), Point(8, 8), ... Point(4, 8)]) >>> fourth_square = Contour([Point(0, 4), Point(4, 4), Point(4, 8), ... Point(0, 8)]) >>> first_inner_square = Contour([Point(1, 1), Point(3, 1), Point(3, 3), ... Point(1, 3)]) >>> second_inner_square = Contour([Point(5, 1), Point(7, 1), Point(7, 3), ... Point(5, 3)]) >>> third_inner_square = Contour([Point(5, 5), Point(7, 5), Point(7, 7), ... Point(5, 7)]) >>> clockwise_first_inner_square = Contour([Point(1, 1), Point(1, 3), ... Point(3, 3), Point(3, 1)]) >>> clockwise_second_inner_square = Contour([Point(5, 1), Point(5, 3), ... Point(7, 3), Point(7, 1)]) >>> clockwise_third_inner_square = Contour([Point(5, 5), Point(5, 7), ... Point(7, 7), Point(7, 5)]) >>> (complete_intersect_multipolygons( ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_inner_square, [])]), ... Multipolygon([Polygon(second_square, []), ... Polygon(fourth_square, [])])) ... is EMPTY) True >>> (complete_intersect_multipolygons( ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_square, [])]), ... Multipolygon([Polygon(third_inner_square, []), ... Polygon(fourth_square, [])])) ... == Multipoint([Point(4, 4)])) True >>> (complete_intersect_multipolygons( ... Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])]), ... Multipolygon([Polygon(second_square, []), ... Polygon(fourth_square, [])])) ... == Multisegment([Segment(Point(0, 4), Point(4, 4)), ... Segment(Point(4, 0), Point(4, 4)), ... Segment(Point(4, 4), Point(8, 4)), ... Segment(Point(4, 4), Point(4, 8))])) True >>> (complete_intersect_multipolygons( ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_inner_square, [])]), ... Multipolygon([Polygon(first_square, ... [clockwise_first_inner_square]), ... Polygon(third_square, ... [clockwise_third_inner_square])])) ... == Multisegment([Segment(Point(1, 1), Point(3, 1)), ... Segment(Point(1, 1), Point(1, 3)), ... Segment(Point(1, 3), Point(3, 3)), ... Segment(Point(3, 1), Point(3, 3)), ... Segment(Point(5, 5), Point(7, 5)), ... Segment(Point(5, 5), Point(5, 7)), ... Segment(Point(5, 7), Point(7, 7)), ... Segment(Point(7, 5), Point(7, 7))])) True >>> (complete_intersect_multipolygons( ... Multipolygon([Polygon(first_square, ... [clockwise_first_inner_square]), ... Polygon(second_inner_square, [])]), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_square, ... [clockwise_second_inner_square])])) ... == Multisegment([Segment(Point(1, 1), Point(3, 1)), ... Segment(Point(1, 1), Point(1, 3)), ... Segment(Point(1, 3), Point(3, 3)), ... Segment(Point(3, 1), Point(3, 3)), ... Segment(Point(4, 0), Point(4, 4)), ... Segment(Point(5, 1), Point(7, 1)), ... Segment(Point(5, 1), Point(5, 3)), ... Segment(Point(5, 3), Point(7, 3)), ... Segment(Point(7, 1), Point(7, 3))])) True >>> (complete_intersect_multipolygons( ... Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])]), ... Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])])) ... == Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])])) True >>> (complete_intersect_multipolygons( ... Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])]), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_inner_square, [])])) ... == complete_intersect_multipolygons( ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_inner_square, [])]), ... Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])])) ... == complete_intersect_multipolygons( ... Multipolygon([Polygon(first_square, []), ... Polygon(third_inner_square, [])]), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_inner_square, [])])) ... == complete_intersect_multipolygons( ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_inner_square, [])]), ... Multipolygon([Polygon(first_square, []), ... Polygon(third_inner_square, [])])) ... == complete_intersect_multipolygons( ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_inner_square, []), ... Polygon(third_inner_square, [])]), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_inner_square, [])])) ... == complete_intersect_multipolygons( ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_inner_square, [])]), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_inner_square, []), ... Polygon(third_inner_square, [])])) ... == Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_inner_square, [])])) True >>> (complete_intersect_multipolygons( ... Multipolygon([Polygon(first_square, []), ... Polygon(second_inner_square, [])]), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_square, ... [clockwise_second_inner_square])])) ... == Mix(EMPTY, Multisegment([Segment(Point(4, 0), Point(4, 4)), ... Segment(Point(5, 1), Point(7, 1)), ... Segment(Point(5, 1), Point(5, 3)), ... Segment(Point(5, 3), Point(7, 3)), ... Segment(Point(7, 1), Point(7, 3))]), ... Polygon(first_inner_square, []))) True >>> (complete_intersect_multipolygons( ... Multipolygon([Polygon(first_square, []), ... Polygon(third_inner_square, [])]), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_square, [])])) ... == Mix(Multipoint([Point(4, 4)]), EMPTY, ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_inner_square, [])]))) True >>> (complete_intersect_multipolygons( ... Multipolygon([Polygon(first_square, []), ... Polygon(second_inner_square, [])]), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_square, [])])) ... == Mix(EMPTY, Segment(Point(4, 0), Point(4, 4)), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_inner_square, [])]))) True """ return _holey.CompleteIntersection( _operands.MultipolygonOperand(first), _operands.MultipolygonOperand(second), _get_context() if context is None else context ).compute()
[docs]def intersect_multipolygons(first: _Multipolygon, second: _Multipolygon, *, context: _Optional[_Context] = None ) -> _Union[_Empty, _Multipolygon, _Polygon]: """ Returns intersection of multipolygons. Time complexity: ``O(segments_count * log segments_count)`` Memory complexity: ``O(segments_count)`` where ``segments_count = edges_count + intersections_count``, ``edges_count = first_edges_count + second_edges_count``, ``first_edges_count = sum(len(polygon.border.vertices)\ + sum(len(hole.vertices) for hole in polygon.holes)\ for polygon in first.polygons)``, ``second_edges_count = sum(len(polygon.border.vertices)\ + sum(len(hole.vertices) for hole in polygon.holes)\ for polygon in second.polygons)``, ``intersections_count`` --- number of intersections between multipolygons edges. :param first: first operand. :param second: second operand. :param context: geometric context. :returns: intersection of operands. >>> from ground.base import get_context >>> context = get_context() >>> EMPTY = context.empty >>> Contour = context.contour_cls >>> Multipolygon = context.multipolygon_cls >>> Point = context.point_cls >>> Polygon = context.polygon_cls >>> first_square = Contour([Point(0, 0), Point(4, 0), Point(4, 4), ... Point(0, 4)]) >>> second_square = Contour([Point(4, 0), Point(8, 0), Point(8, 4), ... Point(4, 4)]) >>> third_square = Contour([Point(4, 4), Point(8, 4), Point(8, 8), ... Point(4, 8)]) >>> fourth_square = Contour([Point(0, 4), Point(4, 4), Point(4, 8), ... Point(0, 8)]) >>> first_inner_square = Contour([Point(1, 1), Point(3, 1), Point(3, 3), ... Point(1, 3)]) >>> second_inner_square = Contour([Point(5, 1), Point(7, 1), Point(7, 3), ... Point(5, 3)]) >>> third_inner_square = Contour([Point(5, 5), Point(7, 5), Point(7, 7), ... Point(5, 7)]) >>> clockwise_first_inner_square = Contour([Point(1, 1), Point(1, 3), ... Point(3, 3), Point(3, 1)]) >>> clockwise_second_inner_square = Contour([Point(5, 1), Point(7, 1), ... Point(7, 3), Point(5, 3)]) >>> clockwise_third_inner_square = Contour([Point(5, 5), Point(5, 7), ... Point(7, 7), Point(7, 5)]) >>> (intersect_multipolygons( ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_inner_square, [])]), ... Multipolygon([Polygon(second_square, []), ... Polygon(fourth_square, [])])) ... is intersect_multipolygons( ... Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])]), ... Multipolygon([Polygon(second_square, []), ... Polygon(fourth_square, [])])) ... is intersect_multipolygons( ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_inner_square, [])]), ... Multipolygon([Polygon(first_square, ... [clockwise_first_inner_square]), ... Polygon(third_square, ... [clockwise_third_inner_square])])) ... is EMPTY) True >>> (intersect_multipolygons( ... Multipolygon([Polygon(first_square, []), ... Polygon(second_inner_square, [])]), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_square, [])])) ... == Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_inner_square, [])])) True >>> (intersect_multipolygons( ... Multipolygon([Polygon(first_square, []), ... Polygon(third_inner_square, [])]), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_square, [])])) ... == intersect_multipolygons( ... Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])]), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_inner_square, [])])) ... == intersect_multipolygons( ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_inner_square, [])]), ... Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])])) ... == intersect_multipolygons( ... Multipolygon([Polygon(first_square, []), ... Polygon(third_inner_square, [])]), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_inner_square, [])])) ... == intersect_multipolygons( ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_inner_square, [])]), ... Multipolygon([Polygon(first_square, []), ... Polygon(third_inner_square, [])])) ... == intersect_multipolygons( ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_inner_square, []), ... Polygon(third_inner_square, [])]), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_inner_square, [])])) ... == intersect_multipolygons( ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_inner_square, [])]), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_inner_square, []), ... Polygon(third_inner_square, [])])) ... == Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_inner_square, [])])) True >>> (intersect_multipolygons(Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])]), ... Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])])) ... == Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])])) True """ return _holey.Intersection( _operands.MultipolygonOperand(first), _operands.MultipolygonOperand(second), _get_context() if context is None else context ).compute()
[docs]def subtract_multipolygons(minuend: _Multipolygon, subtrahend: _Multipolygon, *, context: _Optional[_Context] = None ) -> _Union[_Empty, _Multipolygon, _Polygon]: """ Returns difference of multipolygons. Time complexity: ``O(segments_count * log segments_count)`` Memory complexity: ``O(segments_count)`` where ``segments_count = edges_count + intersections_count``, ``edges_count = minuend_edges_count + subtrahend_edges_count``, ``minuend_edges_count = sum(len(polygon.border.vertices)\ + sum(len(hole.vertices) for hole in polygon.holes)\ for polygon in minuend.polygons)``, ``subtrahend_edges_count = sum(len(polygon.border.vertices)\ + sum(len(hole.vertices) for hole in polygon.holes)\ for polygon in subtrahend.polygons)``, ``intersections_count`` --- number of intersections between multipolygons edges. :param minuend: multipolygon to subtract from. :param subtrahend: multipolygon to subtract. :param context: geometric context. :returns: difference between minuend and subtrahend. >>> from ground.base import get_context >>> context = get_context() >>> EMPTY = context.empty >>> Contour = context.contour_cls >>> Multipolygon = context.multipolygon_cls >>> Point = context.point_cls >>> Polygon = context.polygon_cls >>> first_square = Contour([Point(0, 0), Point(4, 0), Point(4, 4), ... Point(0, 4)]) >>> second_square = Contour([Point(4, 0), Point(8, 0), Point(8, 4), ... Point(4, 4)]) >>> third_square = Contour([Point(4, 4), Point(8, 4), Point(8, 8), ... Point(4, 8)]) >>> fourth_square = Contour([Point(0, 4), Point(4, 4), Point(4, 8), ... Point(0, 8)]) >>> first_inner_square = Contour([Point(1, 1), Point(3, 1), Point(3, 3), ... Point(1, 3)]) >>> second_inner_square = Contour([Point(5, 1), Point(7, 1), Point(7, 3), ... Point(5, 3)]) >>> third_inner_square = Contour([Point(5, 5), Point(7, 5), Point(7, 7), ... Point(5, 7)]) >>> clockwise_first_inner_square = Contour([Point(1, 1), Point(1, 3), ... Point(3, 3), Point(3, 1)]) >>> clockwise_second_inner_square = Contour([Point(5, 1), Point(5, 3), ... Point(7, 3), Point(7, 1)]) >>> clockwise_third_inner_square = Contour([Point(5, 5), Point(5, 7), ... Point(7, 7), Point(7, 5)]) >>> (subtract_multipolygons(Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])]), ... Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])])) ... is subtract_multipolygons( ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_inner_square, [])]), ... Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])])) ... is subtract_multipolygons( ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_inner_square, [])]), ... Multipolygon([Polygon(first_square, []), ... Polygon(third_inner_square, [])])) ... is subtract_multipolygons( ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_inner_square, [])]), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_inner_square, []), ... Polygon(third_inner_square, [])])) ... is EMPTY) True >>> (subtract_multipolygons( ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_inner_square, []), ... Polygon(third_inner_square, [])]), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_inner_square, [])])) ... == Polygon(second_inner_square, [])) True >>> (subtract_multipolygons( ... Multipolygon([Polygon(first_square, []), ... Polygon(second_inner_square, [])]), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_square, [])])) ... == subtract_multipolygons( ... Multipolygon([Polygon(first_square, []), ... Polygon(third_inner_square, [])]), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_square, [])])) ... == subtract_multipolygons( ... Multipolygon([Polygon(first_square, []), ... Polygon(third_inner_square, [])]), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_inner_square, [])])) ... == Polygon(first_square, [clockwise_first_inner_square])) True >>> (subtract_multipolygons( ... Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])]), ... Multipolygon([Polygon(second_square, []), ... Polygon(fourth_square, [])])) ... == Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])])) True >>> (subtract_multipolygons( ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_inner_square, [])]), ... Multipolygon([Polygon(second_square, []), ... Polygon(fourth_square, [])])) ... == subtract_multipolygons( ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_inner_square, [])]), ... Multipolygon([Polygon(first_square, ... [clockwise_first_inner_square]), ... Polygon(third_square, ... [clockwise_third_inner_square])])) ... == Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_inner_square, [])])) True >>> (subtract_multipolygons( ... Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])]), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_inner_square, [])])) ... == Multipolygon([Polygon(first_square, ... [clockwise_first_inner_square]), ... Polygon(third_square, ... [clockwise_third_inner_square])])) True """ return _holey.Difference( _operands.MultipolygonOperand(minuend), _operands.MultipolygonOperand(subtrahend), _get_context() if context is None else context ).compute()
[docs]def symmetric_subtract_multipolygons(first: _Multipolygon, second: _Multipolygon, *, context: _Optional[_Context] = None ) -> _Union[_Empty, _Multipolygon, _Polygon]: """ Returns symmetric difference of multipolygons. Time complexity: ``O(segments_count * log segments_count)`` Memory complexity: ``O(segments_count)`` where ``segments_count = edges_count + intersections_count``, ``edges_count = first_edges_count + second_edges_count``, ``first_edges_count = sum(len(polygon.border.vertices)\ + sum(len(hole.vertices) for hole in polygon.holes)\ for polygon in first.polygons)``, ``second_edges_count = sum(len(polygon.border.vertices)\ + sum(len(hole.vertices) for hole in polygon.holes)\ for polygon in second.polygons)``, ``intersections_count`` --- number of intersections between multipolygons edges. :param first: first operand. :param second: second operand. :param context: geometric context. :returns: symmetric difference of operands. >>> from ground.base import get_context >>> context = get_context() >>> EMPTY = context.empty >>> Contour = context.contour_cls >>> Multipolygon = context.multipolygon_cls >>> Point = context.point_cls >>> Polygon = context.polygon_cls >>> first_square = Contour([Point(0, 0), Point(4, 0), Point(4, 4), ... Point(0, 4)]) >>> second_square = Contour([Point(4, 0), Point(8, 0), Point(8, 4), ... Point(4, 4)]) >>> third_square = Contour([Point(4, 4), Point(8, 4), Point(8, 8), ... Point(4, 8)]) >>> fourth_square = Contour([Point(0, 4), Point(4, 4), Point(4, 8), ... Point(0, 8)]) >>> first_inner_square = Contour([Point(1, 1), Point(3, 1), Point(3, 3), ... Point(1, 3)]) >>> second_inner_square = Contour([Point(5, 1), Point(7, 1), Point(7, 3), ... Point(5, 3)]) >>> third_inner_square = Contour([Point(5, 5), Point(7, 5), Point(7, 7), ... Point(5, 7)]) >>> clockwise_first_inner_square = Contour([Point(1, 1), Point(1, 3), ... Point(3, 3), Point(3, 1)]) >>> clockwise_second_inner_square = Contour([Point(5, 1), Point(5, 3), ... Point(7, 3), Point(7, 1)]) >>> clockwise_third_inner_square = Contour([Point(5, 5), Point(5, 7), ... Point(7, 7), Point(7, 5)]) >>> (symmetric_subtract_multipolygons( ... Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])]), ... Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])])) ... is EMPTY) True >>> (symmetric_subtract_multipolygons( ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_inner_square, [])]), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_inner_square, []), ... Polygon(third_inner_square, [])])) ... == symmetric_subtract_multipolygons( ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_inner_square, []), ... Polygon(third_inner_square, [])]), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_inner_square, [])])) ... == Polygon(second_inner_square, [])) True >>> (symmetric_subtract_multipolygons( ... Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])]), ... Multipolygon([Polygon(second_square, []), ... Polygon(fourth_square, [])])) ... == Polygon(Contour([Point(0, 0), Point(8, 0), Point(8, 8), ... Point(0, 8)]), [])) True >>> (symmetric_subtract_multipolygons( ... Multipolygon([Polygon(first_square, []), ... Polygon(third_inner_square, [])]), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_inner_square, [])])) ... == symmetric_subtract_multipolygons( ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_inner_square, [])]), ... Multipolygon([Polygon(first_square, []), ... Polygon(third_inner_square, [])])) ... == Polygon(first_square, [clockwise_first_inner_square])) True >>> (symmetric_subtract_multipolygons( ... Multipolygon([Polygon(first_square, []), ... Polygon(second_inner_square, [])]), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_square, [])])) ... == Polygon(Contour([Point(0, 0), Point(8, 0), Point(8, 4), ... Point(0, 4)]), ... [clockwise_first_inner_square, ... clockwise_second_inner_square])) True >>> (symmetric_subtract_multipolygons( ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_inner_square, [])]), ... Multipolygon([Polygon(first_square, ... [clockwise_first_inner_square]), ... Polygon(third_square, ... [clockwise_third_inner_square])])) ... == Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])])) True >>> (symmetric_subtract_multipolygons( ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_inner_square, [])]), ... Multipolygon([Polygon(second_square, []), ... Polygon(fourth_square, [])])) ... == Multipolygon([Polygon(fourth_square, []), ... Polygon(first_inner_square, []), ... Polygon(second_square, []), ... Polygon(third_inner_square, [])])) True >>> (symmetric_subtract_multipolygons( ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_inner_square, [])]), ... Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])])) ... == symmetric_subtract_multipolygons( ... Multipolygon([Polygon(first_square, []), ... Polygon(third_inner_square, [])]), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_square, [])])) ... == symmetric_subtract_multipolygons( ... Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])]), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_inner_square, [])])) ... == Multipolygon([Polygon(first_square, ... [clockwise_first_inner_square]), ... Polygon(third_square, ... [clockwise_third_inner_square])])) True """ return _holey.SymmetricDifference( _operands.MultipolygonOperand(first), _operands.MultipolygonOperand(second), _get_context() if context is None else context ).compute()
[docs]def unite_multipolygons(first: _Multipolygon, second: _Multipolygon, *, context: _Optional[_Context] = None ) -> _Union[_Multipolygon, _Polygon]: """ Returns union of multipolygons. Time complexity: ``O(segments_count * log segments_count)`` Memory complexity: ``O(segments_count)`` where ``segments_count = edges_count + intersections_count``, ``edges_count = first_edges_count + second_edges_count``, ``first_edges_count = sum(len(polygon.border.vertices)\ + sum(len(hole.vertices) for hole in polygon.holes)\ for polygon in first.polygons)``, ``second_edges_count = sum(len(polygon.border.vertices)\ + sum(len(hole.vertices) for hole in polygon.holes)\ for polygon in second.polygons)``, ``intersections_count`` --- number of intersections between multipolygons edges. :param first: first operand. :param second: second operand. :param context: geometric context. :returns: union of operands. >>> from ground.base import get_context >>> context = get_context() >>> EMPTY = context.empty >>> Contour = context.contour_cls >>> Multipolygon = context.multipolygon_cls >>> Point = context.point_cls >>> Polygon = context.polygon_cls >>> first_square = Contour([Point(0, 0), Point(4, 0), Point(4, 4), ... Point(0, 4)]) >>> second_square = Contour([Point(4, 0), Point(8, 0), Point(8, 4), ... Point(4, 4)]) >>> third_square = Contour([Point(4, 4), Point(8, 4), Point(8, 8), ... Point(4, 8)]) >>> fourth_square = Contour([Point(0, 4), Point(4, 4), Point(4, 8), ... Point(0, 8)]) >>> first_inner_square = Contour([Point(1, 1), Point(3, 1), Point(3, 3), ... Point(1, 3)]) >>> second_inner_square = Contour([Point(5, 1), Point(7, 1), Point(7, 3), ... Point(5, 3)]) >>> third_inner_square = Contour([Point(5, 5), Point(7, 5), Point(7, 7), ... Point(5, 7)]) >>> clockwise_first_inner_square = Contour([Point(1, 1), Point(1, 3), ... Point(3, 3), Point(3, 1)]) >>> clockwise_second_inner_square = Contour([Point(5, 1), Point(7, 1), ... Point(7, 3), Point(5, 3)]) >>> clockwise_third_inner_square = Contour([Point(5, 5), Point(5, 7), ... Point(7, 7), Point(7, 5)]) >>> (unite_multipolygons(Multipolygon([Polygon(first_square, []), ... Polygon(second_inner_square, [])]), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_square, [])])) ... == Polygon(Contour([Point(0, 0), Point(8, 0), Point(8, 4), ... Point(0, 4)]), [])) True >>> (unite_multipolygons(Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])]), ... Multipolygon([Polygon(second_square, []), ... Polygon(fourth_square, [])])) ... == Polygon(Contour([Point(0, 0), Point(8, 0), Point(8, 8), ... Point(0, 8)]), [])) True >>> (unite_multipolygons(Multipolygon([Polygon(first_square, []), ... Polygon(third_inner_square, [])]), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_inner_square, [])])) ... == unite_multipolygons( ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_inner_square, [])]), ... Multipolygon([Polygon(first_square, []), ... Polygon(third_inner_square, [])])) ... == Multipolygon([Polygon(first_square, []), ... Polygon(third_inner_square, [])])) True >>> (unite_multipolygons(Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])]), ... Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])])) ... == unite_multipolygons( ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_inner_square, [])]), ... Multipolygon([Polygon(first_square, ... [clockwise_first_inner_square]), ... Polygon(third_square, ... [clockwise_third_inner_square])])) ... == unite_multipolygons(Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_inner_square, [])]), ... Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])])) ... == unite_multipolygons(Multipolygon([Polygon(first_square, []), ... Polygon(third_inner_square, [])]), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_square, [])])) ... == unite_multipolygons( ... Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])]), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_inner_square, [])])) ... == Multipolygon([Polygon(first_square, []), ... Polygon(third_square, [])])) True >>> (unite_multipolygons(Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_inner_square, [])]), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_inner_square, []), ... Polygon(third_inner_square, [])])) ... == unite_multipolygons( ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_inner_square, []), ... Polygon(third_inner_square, [])]), ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_inner_square, [])])) ... == Multipolygon([Polygon(first_inner_square, []), ... Polygon(second_inner_square, []), ... Polygon(third_inner_square, [])])) True >>> (unite_multipolygons( ... Multipolygon([Polygon(first_inner_square, []), ... Polygon(third_inner_square, [])]), ... Multipolygon([Polygon(second_square, []), ... Polygon(fourth_square, [])])) ... == Multipolygon([Polygon(fourth_square, []), ... Polygon(first_inner_square, []), ... Polygon(second_square, []), ... Polygon(third_inner_square, [])])) True """ return _holey.Union( _operands.MultipolygonOperand(first), _operands.MultipolygonOperand(second), _get_context() if context is None else context ).compute()