Welcome to clipping’s documentation!

Note

If object is not listed in documentation it should be considered as implementation detail that can change and should not be relied upon.

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.

clipping.planar.intersect_segments(first: ground.hints.Segment, second: ground.hints.Segment, *, context: Optional[ground.base.Context] = None)Union[ground.hints.Empty, ground.hints.Multipoint, ground.hints.Segment][source]

Returns intersection of segments.

Time complexity:

O(1)

Memory complexity:

O(1)

Parameters
  • first – first operand.

  • second – second operand.

  • 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
clipping.planar.subtract_segments(minuend: ground.hints.Segment, subtrahend: ground.hints.Segment, *, context: Optional[ground.base.Context] = None)Union[ground.hints.Empty, ground.hints.Multisegment, ground.hints.Segment][source]

Returns difference of segments.

Time complexity:

O(1)

Memory complexity:

O(1)

Parameters
  • minuend – segment to subtract from.

  • subtrahend – segment to subtract.

  • 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
clipping.planar.symmetric_subtract_segments(first: ground.hints.Segment, second: ground.hints.Segment, *, context: Optional[ground.base.Context] = None)Union[ground.hints.Empty, ground.hints.Multisegment, ground.hints.Segment][source]

Returns symmetric difference of segments.

Time complexity:

O(1)

Memory complexity:

O(1)

Parameters
  • first – first operand.

  • second – second operand.

  • 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
clipping.planar.unite_segments(first: ground.hints.Segment, second: ground.hints.Segment, *, context: Optional[ground.base.Context] = None)Union[ground.hints.Multisegment, ground.hints.Segment][source]

Returns union of segments.

Time complexity:

O(1)

Memory complexity:

O(1)

Parameters
  • first – first operand.

  • second – second operand.

  • 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
clipping.planar.complete_intersect_segment_with_multisegment(segment: ground.hints.Segment, multisegment: ground.hints.Multisegment, *, context: Optional[ground.base.Context] = None)Union[ground.hints.Empty, ground.hints.Mix, ground.hints.Multipoint, ground.hints.Multisegment, ground.hints.Segment][source]

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.

Parameters
  • segment – first operand.

  • multisegment – second operand.

  • 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
clipping.planar.intersect_segment_with_multisegment(segment: ground.hints.Segment, multisegment: ground.hints.Multisegment, *, context: Optional[ground.base.Context] = None)Union[ground.hints.Empty, ground.hints.Multisegment, ground.hints.Segment][source]

Returns intersection of segments.

Time complexity:

O(len(multisegment.segments))

Memory complexity:

O(len(multisegment.segments))

Parameters
  • segment – first operand.

  • multisegment – second operand.

  • 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
clipping.planar.subtract_multisegment_from_segment(minuend: ground.hints.Segment, subtrahend: ground.hints.Multisegment, *, context: Optional[ground.base.Context] = None)Union[ground.hints.Empty, ground.hints.Multisegment, ground.hints.Segment][source]

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.

Parameters
  • minuend – segment to subtract from.

  • subtrahend – multisegment to subtract.

  • 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
clipping.planar.subtract_segment_from_multisegment(minuend: ground.hints.Multisegment, subtrahend: ground.hints.Segment, *, context: Optional[ground.base.Context] = None)Union[ground.hints.Empty, ground.hints.Multisegment, ground.hints.Segment][source]

Returns difference of segment with multisegment.

Time complexity:

O(len(subtrahend.segments))

Memory complexity:

O(len(subtrahend.segments))

Parameters
  • minuend – multisegment to subtract from.

  • subtrahend – segment to subtract.

  • 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
clipping.planar.symmetric_subtract_multisegment_from_segment(first: ground.hints.Segment, second: ground.hints.Multisegment, *, context: Optional[ground.base.Context] = None)Union[ground.hints.Empty, ground.hints.Multisegment, ground.hints.Segment][source]

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.

Parameters
  • first – first operand.

  • second – second operand.

  • 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
clipping.planar.unite_segment_with_multisegment(first: ground.hints.Segment, second: ground.hints.Multisegment, *, context: Optional[ground.base.Context] = None)Union[ground.hints.Multisegment, ground.hints.Segment][source]

Returns symmetric difference of segment and multisegment.

Time complexity:

O(len(second.segments))

Memory complexity:

O(len(second.segments))

Parameters
  • first – first operand.

  • second – second operand.

  • 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
clipping.planar.complete_intersect_segment_with_polygon(segment: ground.hints.Segment, polygon: ground.hints.Polygon, *, context: Optional[ground.base.Context] = None)Union[ground.hints.Empty, ground.hints.Mix, ground.hints.Multipoint, ground.hints.Multisegment, ground.hints.Segment][source]

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.

Parameters
  • segment – first operand.

  • polygon – second operand.

  • 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
clipping.planar.intersect_segment_with_polygon(segment: ground.hints.Segment, polygon: ground.hints.Polygon, *, context: Optional[ground.base.Context] = None)Union[ground.hints.Empty, ground.hints.Multisegment, ground.hints.Segment][source]

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.

Parameters
  • segment – first operand.

  • polygon – second operand.

  • 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
clipping.planar.subtract_polygon_from_segment(minuend: ground.hints.Segment, subtrahend: ground.hints.Polygon, *, context: Optional[ground.base.Context] = None)Union[ground.hints.Empty, ground.hints.Multisegment, ground.hints.Segment][source]

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.

Parameters
  • minuend – segment to subtract from.

  • subtrahend – polygon to subtract.

  • 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
clipping.planar.symmetric_subtract_polygon_from_segment(segment: ground.hints.Segment, polygon: ground.hints.Polygon, *, context: Optional[ground.base.Context] = None)Union[ground.hints.Mix, ground.hints.Polygon][source]

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.

Parameters
  • segment – first operand.

  • polygon – second operand.

  • 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
clipping.planar.unite_segment_with_polygon(segment: ground.hints.Segment, polygon: ground.hints.Polygon, *, context: Optional[ground.base.Context] = None)Union[ground.hints.Mix, ground.hints.Polygon][source]

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.

Parameters
  • segment – first operand.

  • polygon – second operand.

  • 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
clipping.planar.complete_intersect_segment_with_multipolygon(segment: ground.hints.Segment, multipolygon: ground.hints.Multipolygon, *, context: Optional[ground.base.Context] = None)Union[ground.hints.Empty, ground.hints.Mix, ground.hints.Multipoint, ground.hints.Multisegment, ground.hints.Segment][source]

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.

Parameters
  • segment – first operand.

  • multipolygon – second operand.

  • 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
clipping.planar.intersect_segment_with_multipolygon(segment: ground.hints.Segment, multipolygon: ground.hints.Multipolygon, *, context: Optional[ground.base.Context] = None)Union[ground.hints.Empty, ground.hints.Multisegment, ground.hints.Segment][source]

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.

Parameters
  • segment – first operand.

  • multipolygon – second operand.

  • 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
clipping.planar.subtract_multipolygon_from_segment(minuend: ground.hints.Segment, subtrahend: ground.hints.Multipolygon, *, context: Optional[ground.base.Context] = None)Union[ground.hints.Empty, ground.hints.Multisegment, ground.hints.Segment][source]

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.

Parameters
  • minuend – segment to subtract from.

  • subtrahend – multipolygon to subtract.

  • 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
clipping.planar.symmetric_subtract_multipolygon_from_segment(segment: ground.hints.Segment, multipolygon: ground.hints.Multipolygon, *, context: Optional[ground.base.Context] = None)Union[ground.hints.Mix, ground.hints.Multipolygon][source]

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.

Parameters
  • segment – first operand.

  • multipolygon – second operand.

  • 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
clipping.planar.unite_segment_with_multipolygon(segment: ground.hints.Segment, multipolygon: ground.hints.Multipolygon, *, context: Optional[ground.base.Context] = None)Union[ground.hints.Mix, ground.hints.Multipolygon][source]

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.

Parameters
  • segment – first operand.

  • multipolygon – second operand.

  • 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
clipping.planar.segments_to_multisegment(segments: Sequence[ground.hints.Segment], *, context: Optional[ground.base.Context] = None)Union[ground.hints.Empty, ground.hints.Segment, ground.hints.Multisegment][source]

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.

Parameters
  • segments – target segments.

  • 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
clipping.planar.complete_intersect_multisegments(first: ground.hints.Multisegment, second: ground.hints.Multisegment, *, context: Optional[ground.base.Context] = None)Union[ground.hints.Empty, ground.hints.Mix, ground.hints.Multipoint, ground.hints.Multisegment, ground.hints.Segment][source]

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.

Parameters
  • first – first operand.

  • second – second operand.

  • 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
clipping.planar.intersect_multisegments(first: ground.hints.Multisegment, second: ground.hints.Multisegment, *, context: Optional[ground.base.Context] = None)Union[ground.hints.Empty, ground.hints.Segment, ground.hints.Multisegment][source]

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.

Parameters
  • first – first operand.

  • second – second operand.

  • 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
clipping.planar.subtract_multisegments(minuend: ground.hints.Multisegment, subtrahend: ground.hints.Multisegment, *, context: Optional[ground.base.Context] = None)Union[ground.hints.Empty, ground.hints.Segment, ground.hints.Multisegment][source]

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.

Parameters
  • minuend – multisegment to subtract from.

  • subtrahend – multisegment to subtract.

  • 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
clipping.planar.symmetric_subtract_multisegments(first: ground.hints.Multisegment, second: ground.hints.Multisegment, *, context: Optional[ground.base.Context] = None)Union[ground.hints.Empty, ground.hints.Segment, ground.hints.Multisegment][source]

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.

Parameters
  • first – first operand.

  • second – second operand.

  • 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
clipping.planar.unite_multisegments(first: ground.hints.Multisegment, second: ground.hints.Multisegment, *, context: Optional[ground.base.Context] = None)ground.hints.Multisegment[source]

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.

Parameters
  • first – first operand.

  • second – second operand.

  • 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
clipping.planar.complete_intersect_multisegment_with_polygon(multisegment: ground.hints.Multisegment, polygon: ground.hints.Polygon, *, context: Optional[ground.base.Context] = None)Union[ground.hints.Empty, ground.hints.Mix, ground.hints.Multipoint, ground.hints.Multisegment, ground.hints.Segment][source]

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.

Parameters
  • multisegment – multisegment to intersect with.

  • polygon – polygon to intersect with.

  • 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
clipping.planar.intersect_multisegment_with_polygon(multisegment: ground.hints.Multisegment, polygon: ground.hints.Polygon, *, context: Optional[ground.base.Context] = None)Union[ground.hints.Empty, ground.hints.Multisegment, ground.hints.Segment][source]

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.

Parameters
  • multisegment – multisegment to intersect with.

  • polygon – polygon to intersect with.

  • 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
clipping.planar.subtract_polygon_from_multisegment(minuend: ground.hints.Multisegment, subtrahend: ground.hints.Polygon, *, context: Optional[ground.base.Context] = None)Union[ground.hints.Empty, ground.hints.Multisegment, ground.hints.Segment][source]

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.

Parameters
  • minuend – multisegment to subtract from.

  • subtrahend – polygon to subtract.

  • 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
clipping.planar.symmetric_subtract_polygon_from_multisegment(multisegment: ground.hints.Multisegment, polygon: ground.hints.Polygon, *, context: Optional[ground.base.Context] = None)Union[ground.hints.Mix, ground.hints.Polygon][source]

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.

Parameters
  • multisegment – first operand.

  • polygon – second operand.

  • 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
clipping.planar.unite_multisegment_with_polygon(multisegment: ground.hints.Multisegment, polygon: ground.hints.Polygon, *, context: Optional[ground.base.Context] = None)Union[ground.hints.Mix, ground.hints.Polygon][source]

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.

Parameters
  • multisegment – first operand.

  • polygon – second operand.

  • 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
clipping.planar.complete_intersect_multisegment_with_multipolygon(multisegment: ground.hints.Multisegment, multipolygon: ground.hints.Multipolygon, *, context: Optional[ground.base.Context] = None)Union[ground.hints.Empty, ground.hints.Mix, ground.hints.Multipoint, ground.hints.Multisegment, ground.hints.Segment][source]

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.

Parameters
  • multisegment – multisegment to intersect with.

  • multipolygon – multipolygon to intersect with.

  • 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
clipping.planar.intersect_multisegment_with_multipolygon(multisegment: ground.hints.Multisegment, multipolygon: ground.hints.Multipolygon, *, context: Optional[ground.base.Context] = None)Union[ground.hints.Empty, ground.hints.Multisegment, ground.hints.Segment][source]

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.

Parameters
  • multisegment – multisegment to intersect with.

  • multipolygon – multipolygon to intersect with.

  • 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
clipping.planar.subtract_multipolygon_from_multisegment(minuend: ground.hints.Multisegment, subtrahend: ground.hints.Multipolygon, *, context: Optional[ground.base.Context] = None)Union[ground.hints.Empty, ground.hints.Multisegment, ground.hints.Segment][source]

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.

Parameters
  • minuend – multisegment to subtract from.

  • subtrahend – multipolygon to subtract.

  • 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
clipping.planar.symmetric_subtract_multipolygon_from_multisegment(multisegment: ground.hints.Multisegment, multipolygon: ground.hints.Multipolygon, *, context: Optional[ground.base.Context] = None)Union[ground.hints.Mix, ground.hints.Multipolygon][source]

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.

Parameters
  • multisegment – first operand.

  • multipolygon – second operand.

  • 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
clipping.planar.unite_multisegment_with_multipolygon(multisegment: ground.hints.Multisegment, multipolygon: ground.hints.Multipolygon, *, context: Optional[ground.base.Context] = None)Union[ground.hints.Mix, ground.hints.Multipolygon][source]

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.

Parameters
  • multisegment – first operand.

  • multipolygon – second operand.

  • 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
clipping.planar.complete_intersect_regions(first: ground.hints.Contour, second: ground.hints.Contour, *, context: Optional[ground.base.Context] = None)Union[ground.hints.Empty, ground.hints.Mix, ground.hints.Multipoint, ground.hints.Multipolygon, ground.hints.Multisegment, ground.hints.Polygon, ground.hints.Segment][source]

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.

Parameters
  • first – first operand.

  • second – second operand.

  • 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
clipping.planar.intersect_regions(first: ground.hints.Contour, second: ground.hints.Contour, *, context: Optional[ground.base.Context] = None)Union[ground.hints.Empty, ground.hints.Multipolygon, ground.hints.Polygon][source]

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.

Parameters
  • first – first operand.

  • second – second operand.

  • 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
clipping.planar.complete_intersect_region_with_multiregion(region: ground.hints.Contour, multiregion: Sequence[ground.hints.Contour], *, context: Optional[ground.base.Context] = None)Union[ground.hints.Empty, ground.hints.Mix, ground.hints.Multipoint, ground.hints.Multipolygon, ground.hints.Multisegment, ground.hints.Polygon, ground.hints.Segment][source]

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.

Parameters
  • region – first operand.

  • multiregion – second operand.

  • 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
clipping.planar.intersect_region_with_multiregion(region: ground.hints.Contour, multiregion: Sequence[ground.hints.Contour], *, context: Optional[ground.base.Context] = None)Union[ground.hints.Empty, ground.hints.Multipolygon, ground.hints.Polygon][source]

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.

Parameters
  • region – first operand.

  • multiregion – second operand.

  • 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
clipping.planar.complete_intersect_multiregions(first: Sequence[ground.hints.Contour], second: Sequence[ground.hints.Contour], *, context: Optional[ground.base.Context] = None)Union[ground.hints.Empty, ground.hints.Mix, ground.hints.Multipoint, ground.hints.Multipolygon, ground.hints.Multisegment, ground.hints.Polygon, ground.hints.Segment][source]

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.

Parameters
  • first – first operand.

  • second – second operand.

  • 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
clipping.planar.intersect_multiregions(first: Sequence[ground.hints.Contour], second: Sequence[ground.hints.Contour], *, context: Optional[ground.base.Context] = None)Union[ground.hints.Empty, ground.hints.Multipolygon, ground.hints.Polygon][source]

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.

Parameters
  • first – first operand.

  • second – second operand.

  • 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
clipping.planar.complete_intersect_polygons(first: ground.hints.Polygon, second: ground.hints.Polygon, *, context: Optional[ground.base.Context] = None)Union[ground.hints.Empty, ground.hints.Mix, ground.hints.Multipoint, ground.hints.Multisegment, ground.hints.Polygon, ground.hints.Segment][source]

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.

Parameters
  • first – first operand.

  • second – second operand.

  • 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
clipping.planar.intersect_polygons(first: ground.hints.Polygon, second: ground.hints.Polygon, *, context: Optional[ground.base.Context] = None)Union[ground.hints.Empty, ground.hints.Multipolygon, ground.hints.Polygon][source]

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.

Parameters
  • first – first operand.

  • second – second operand.

  • 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
clipping.planar.subtract_polygons(minuend: ground.hints.Polygon, subtrahend: ground.hints.Polygon, *, context: Optional[ground.base.Context] = None)Union[ground.hints.Empty, ground.hints.Multipolygon, ground.hints.Polygon][source]

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.

Parameters
  • minuend – polygon to subtract from.

  • subtrahend – polygon to subtract.

  • 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
clipping.planar.symmetric_subtract_polygons(first: ground.hints.Polygon, second: ground.hints.Polygon, *, context: Optional[ground.base.Context] = None)Union[ground.hints.Empty, ground.hints.Multipolygon, ground.hints.Polygon][source]

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.

Parameters
  • first – first operand.

  • second – second operand.

  • 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
clipping.planar.unite_polygons(first: ground.hints.Polygon, second: ground.hints.Polygon, *, context: Optional[ground.base.Context] = None)Union[ground.hints.Multipolygon, ground.hints.Polygon][source]

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.

Parameters
  • first – first operand.

  • second – second operand.

  • 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
clipping.planar.complete_intersect_polygon_with_multipolygon(polygon: ground.hints.Polygon, multipolygon: ground.hints.Multipolygon, *, context: Optional[ground.base.Context] = None)Union[ground.hints.Empty, ground.hints.Mix, ground.hints.Multipoint, ground.hints.Multipolygon, ground.hints.Multisegment, ground.hints.Polygon, ground.hints.Segment][source]

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.

Parameters
  • polygon – first operand.

  • multipolygon – second operand.

  • 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
clipping.planar.intersect_polygon_with_multipolygon(polygon: ground.hints.Polygon, multipolygon: ground.hints.Multipolygon, *, context: Optional[ground.base.Context] = None)Union[ground.hints.Empty, ground.hints.Multipolygon, ground.hints.Polygon][source]

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.

Parameters
  • polygon – first operand.

  • multipolygon – second operand.

  • 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
clipping.planar.subtract_multipolygon_from_polygon(minuend: ground.hints.Polygon, subtrahend: ground.hints.Multipolygon, *, context: Optional[ground.base.Context] = None)Union[ground.hints.Empty, ground.hints.Multipolygon, ground.hints.Polygon][source]

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.

Parameters
  • minuend – polygon to subtract from.

  • subtrahend – multipolygon to subtract.

  • 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
clipping.planar.subtract_polygon_from_multipolygon(minuend: ground.hints.Multipolygon, subtrahend: ground.hints.Polygon, *, context: Optional[ground.base.Context] = None)Union[ground.hints.Empty, ground.hints.Multipolygon, ground.hints.Polygon][source]

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.

Parameters
  • minuend – multipolygon to subtract from.

  • subtrahend – polygon to subtract.

  • 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
clipping.planar.symmetric_subtract_multipolygon_from_polygon(polygon: ground.hints.Polygon, multipolygon: ground.hints.Multipolygon, *, context: Optional[ground.base.Context] = None)Union[ground.hints.Multipolygon, ground.hints.Polygon][source]

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.

Parameters
  • polygon – first operand.

  • multipolygon – second operand.

  • 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
clipping.planar.unite_polygon_with_multipolygon(polygon: ground.hints.Polygon, multipolygon: ground.hints.Multipolygon, *, context: Optional[ground.base.Context] = None)Union[ground.hints.Multipolygon, ground.hints.Polygon][source]

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.

Parameters
  • polygon – first operand.

  • multipolygon – second operand.

  • 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
clipping.planar.complete_intersect_multipolygons(first: ground.hints.Multipolygon, second: ground.hints.Multipolygon, *, context: Optional[ground.base.Context] = None)Union[ground.hints.Empty, ground.hints.Mix, ground.hints.Multipoint, ground.hints.Multipolygon, ground.hints.Multisegment, ground.hints.Polygon, ground.hints.Segment][source]

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.

Parameters
  • first – first operand.

  • second – second operand.

  • 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
clipping.planar.intersect_multipolygons(first: ground.hints.Multipolygon, second: ground.hints.Multipolygon, *, context: Optional[ground.base.Context] = None)Union[ground.hints.Empty, ground.hints.Multipolygon, ground.hints.Polygon][source]

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.

Parameters
  • first – first operand.

  • second – second operand.

  • 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
clipping.planar.subtract_multipolygons(minuend: ground.hints.Multipolygon, subtrahend: ground.hints.Multipolygon, *, context: Optional[ground.base.Context] = None)Union[ground.hints.Empty, ground.hints.Multipolygon, ground.hints.Polygon][source]

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.

Parameters
  • minuend – multipolygon to subtract from.

  • subtrahend – multipolygon to subtract.

  • 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
clipping.planar.symmetric_subtract_multipolygons(first: ground.hints.Multipolygon, second: ground.hints.Multipolygon, *, context: Optional[ground.base.Context] = None)Union[ground.hints.Empty, ground.hints.Multipolygon, ground.hints.Polygon][source]

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.

Parameters
  • first – first operand.

  • second – second operand.

  • 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
clipping.planar.unite_multipolygons(first: ground.hints.Multipolygon, second: ground.hints.Multipolygon, *, context: Optional[ground.base.Context] = None)Union[ground.hints.Multipolygon, ground.hints.Polygon][source]

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.

Parameters
  • first – first operand.

  • second – second operand.

  • 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