import enum as _enum
from contextvars import ContextVar as _ContextVar
from numbers import Rational as _Rational
from typing import (Optional as _Optional,
Sequence as _Sequence,
Type as _Type,
Union as _Union)
from reprit import serializers as _serializers
from reprit.base import generate_repr as _generate_repr
from symba.base import sqrt as _sqrt
from . import hints as _hints
from .core import (angular as _angular,
boxed as _boxed,
centroidal as _centroidal,
circular as _circular,
discrete as _discrete,
enums as _enums,
geometries as _geometries,
measured as _measured,
metric as _metric,
rotation as _rotation,
scaling as _scaling,
segment as _segment,
translation as _translation,
vector as _vector)
from .core.hints import (QuaternaryPointFunction as _QuaternaryPointFunction,
SquareRooter as _SquareRooter,
TernaryPointFunction as _TernaryPointFunction)
_QuaternaryFunction = _QuaternaryPointFunction[_hints.Scalar]
_TernaryFunction = _TernaryPointFunction[_hints.Scalar]
Location = _enums.Location
Kind = _enums.Kind
Orientation = _enums.Orientation
Relation = _enums.Relation
[docs]@_enum.unique
class Mode(_enums.Base):
"""Represents possible context modes."""
EXACT = 0
PLAIN = 1
ROBUST = 2
[docs]class Context:
"""Represents common language for computational geometry."""
__slots__ = ('_angular', '_box_cls', '_centroidal', '_circular',
'_contour_cls', '_empty', '_empty_cls', '_measured',
'_metric', '_mix_cls', '_mode', '_multipoint_cls',
'_multipolygon_cls', '_multisegment_cls', '_origin',
'_point_cls', '_polygon_cls', '_rotation', '_scaling',
'_segment', '_segment_cls', '_sqrt', '_translation',
'_vector')
def __init__(self,
*,
box_cls: _Type[_hints.Box] = _geometries.Box,
contour_cls: _Type[_hints.Contour] = _geometries.Contour,
empty_cls: _Type[_hints.Empty] = _geometries.Empty,
mix_cls: _Type[_hints.Mix] = _geometries.Mix,
multipoint_cls: _Type[_hints.Multipoint]
= _geometries.Multipoint,
multipolygon_cls: _Type[_hints.Multipolygon]
= _geometries.Multipolygon,
multisegment_cls: _Type[_hints.Multisegment]
= _geometries.Multisegment,
point_cls: _Type[_hints.Point] = _geometries.Point,
polygon_cls: _Type[_hints.Polygon] = _geometries.Polygon,
segment_cls: _Type[_hints.Segment] = _geometries.Segment,
mode: Mode = Mode.EXACT,
sqrt: _SquareRooter = _sqrt) -> None:
self._box_cls = box_cls
self._contour_cls = contour_cls
self._empty, self._empty_cls = empty_cls(), empty_cls
self._mix_cls = mix_cls
self._multipoint_cls = multipoint_cls
self._multipolygon_cls = multipolygon_cls
self._multisegment_cls = multisegment_cls
self._origin = point_cls(0, 0)
self._point_cls = point_cls
self._polygon_cls = polygon_cls
self._segment_cls = segment_cls
self._mode = mode
self._sqrt = sqrt
(self._angular, self._centroidal, self._circular, self._measured,
self._metric, self._rotation, self._scaling, self._segment,
self._translation, self._vector) = (
(_angular.exact_context, _centroidal.exact_context,
_circular.exact_context, _measured.exact_context,
_metric.exact_context, _rotation.exact_context,
_scaling.exact_context, _segment.exact_context,
_translation.exact_context, _vector.exact_context)
if mode is Mode.EXACT
else ((_angular.plain_context, _centroidal.plain_context,
_circular.plain_context, _measured.plain_context,
_metric.plain_context, _rotation.plain_context,
_scaling.plain_context, _segment.plain_context,
_translation.plain_context, _vector.plain_context)
if mode is Mode.PLAIN
else (_angular.robust_context, _centroidal.robust_context,
_circular.robust_context, _measured.robust_context,
_metric.robust_context, _rotation.robust_context,
_scaling.robust_context, _segment.exact_context,
_translation.robust_context, _vector.robust_context)))
__repr__ = _generate_repr(__init__,
argument_serializer=_serializers.complex_,
skip_defaults=True)
@property
def angle_kind(self) -> _TernaryPointFunction[Kind]:
"""
Returns function for computing angle kind.
Time complexity:
``O(1)``
Memory complexity:
``O(1)``
>>> context = get_context()
>>> Point = context.point_cls
>>> (context.angle_kind(Point(0, 0), Point(1, 0), Point(-1, 0))
... is Kind.OBTUSE)
True
>>> (context.angle_kind(Point(0, 0), Point(1, 0), Point(0, 1))
... is Kind.RIGHT)
True
>>> (context.angle_kind(Point(0, 0), Point(1, 0), Point(1, 0))
... is Kind.ACUTE)
True
"""
return self._angular.kind
@property
def angle_orientation(self) -> _TernaryPointFunction[Orientation]:
"""
Returns function for computing angle orientation.
Time complexity:
``O(1)``
Memory complexity:
``O(1)``
>>> context = get_context()
>>> Point = context.point_cls
>>> (context.angle_orientation(Point(0, 0), Point(0, 1), Point(1, 0))
... is Orientation.CLOCKWISE)
True
>>> (context.angle_orientation(Point(0, 0), Point(1, 0), Point(1, 0))
... is Orientation.COLLINEAR)
True
>>> (context.angle_orientation(Point(0, 0), Point(1, 0), Point(0, 1))
... is Orientation.COUNTERCLOCKWISE)
True
"""
return self._angular.orientation
@property
def box_cls(self) -> _Type[_hints.Box]:
"""Returns type for boxes."""
return self._box_cls
@property
def box_point_squared_distance(self) -> _metric.BoxPointMetric:
"""
Returns squared Euclidean distance between box and a point.
Time complexity:
``O(1)``
Memory complexity:
``O(1)``
>>> context = get_context()
>>> Box, Point = context.box_cls, context.point_cls
>>> context.box_point_squared_distance(Box(0, 1, 0, 1),
... Point(1, 1)) == 0
True
>>> context.box_point_squared_distance(Box(0, 1, 0, 1),
... Point(2, 1)) == 1
True
>>> context.box_point_squared_distance(Box(0, 1, 0, 1),
... Point(2, 2)) == 2
True
"""
return self._metric.box_point_squared_metric
@property
def contour_cls(self) -> _Type[_hints.Contour]:
"""Returns type for contours."""
return self._contour_cls
@property
def cross_product(self) -> _QuaternaryFunction:
"""
Returns cross product of the segments.
Time complexity:
``O(1)``
Memory complexity:
``O(1)``
>>> context = get_context()
>>> Point = context.point_cls
>>> context.cross_product(Point(0, 0), Point(0, 1), Point(0, 0),
... Point(1, 0)) == -1
True
>>> context.cross_product(Point(0, 0), Point(1, 0), Point(0, 0),
... Point(1, 0)) == 0
True
>>> context.cross_product(Point(0, 0), Point(1, 0), Point(0, 0),
... Point(0, 1)) == 1
True
"""
return self._vector.cross_product
@property
def dot_product(self) -> _QuaternaryFunction:
"""
Returns dot product of the segments.
Time complexity:
``O(1)``
Memory complexity:
``O(1)``
>>> context = get_context()
>>> Point = context.point_cls
>>> context.dot_product(Point(0, 0), Point(1, 0), Point(0, 0),
... Point(-1, 0)) == -1
True
>>> context.dot_product(Point(0, 0), Point(1, 0), Point(0, 0),
... Point(0, 1)) == 0
True
>>> context.dot_product(Point(0, 0), Point(1, 0), Point(0, 0),
... Point(1, 0)) == 1
True
"""
return self._vector.dot_product
@property
def empty(self) -> _hints.Empty:
"""Returns an empty geometry."""
return self._empty
@property
def empty_cls(self) -> _Type[_hints.Empty]:
"""Returns type for empty geometries."""
return self._empty_cls
@property
def mix_cls(self) -> _Type[_hints.Mix]:
"""Returns type for mixes."""
return self._mix_cls
@property
def mode(self) -> Mode:
"""Returns mode of the context."""
return self._mode
@property
def multipoint_cls(self) -> _Type[_hints.Multipoint]:
"""Returns type for multipoints."""
return self._multipoint_cls
@property
def multipolygon_cls(self) -> _Type[_hints.Multipolygon]:
"""Returns type for multipolygons."""
return self._multipolygon_cls
@property
def multisegment_cls(self) -> _Type[_hints.Multisegment]:
"""Returns type for multisegments."""
return self._multisegment_cls
@property
def origin(self) -> _hints.Point:
"""Returns origin."""
return self._origin
@property
def point_cls(self) -> _Type[_hints.Point]:
"""Returns type for points."""
return self._point_cls
@property
def locate_point_in_point_point_point_circle(
self) -> _circular.PointPointPointLocator:
"""
Returns location of point in point-point-point circle.
Time complexity:
``O(1)``
Memory complexity:
``O(1)``
>>> context = get_context()
>>> Point = context.point_cls
>>> (context.locate_point_in_point_point_point_circle(
... Point(1, 1), Point(0, 0), Point(2, 0), Point(0, 2))
... is Location.INTERIOR)
True
>>> (context.locate_point_in_point_point_point_circle(
... Point(2, 2), Point(0, 0), Point(2, 0), Point(0, 2))
... is Location.BOUNDARY)
True
>>> (context.locate_point_in_point_point_point_circle(
... Point(3, 3), Point(0, 0), Point(2, 0), Point(0, 2))
... is Location.EXTERIOR)
True
"""
return self._circular.point_point_point_locator
@property
def points_squared_distance(self) -> _metric.PointPointMetric:
"""
Returns squared Euclidean distance between two points.
Time complexity:
``O(1)``
Memory complexity:
``O(1)``
>>> context = get_context()
>>> Point = context.point_cls
>>> context.points_squared_distance(Point(0, 0), Point(0, 0)) == 0
True
>>> context.points_squared_distance(Point(0, 0), Point(1, 0)) == 1
True
>>> context.points_squared_distance(Point(0, 1), Point(1, 0)) == 2
True
"""
return self._metric.point_point_squared_metric
@property
def polygon_cls(self) -> _Type[_hints.Polygon]:
"""Returns type for polygons."""
return self._polygon_cls
@property
def region_signed_area(self) -> _measured.RegionSignedMeasure:
"""
Returns signed area of the region given its contour.
Time complexity:
``O(len(contour.vertices))``
Memory complexity:
``O(1)``
>>> context = get_context()
>>> Contour = context.contour_cls
>>> Point = context.point_cls
>>> (context.region_signed_area(Contour([Point(0, 0), Point(1, 0),
... Point(1, 1), Point(0, 1)]))
... == 1)
True
>>> (context.region_signed_area(Contour([Point(0, 0), Point(0, 1),
... Point(1, 1), Point(1, 0)]))
... == -1)
True
"""
return self._measured.region_signed_area
@property
def segment_cls(self) -> _Type[_hints.Segment]:
"""Returns type for segments."""
return self._segment_cls
@property
def sqrt(self) -> _SquareRooter:
"""Returns function for computing square root."""
return self._sqrt
[docs] def box_segment_squared_distance(self,
box: _hints.Box,
segment: _hints.Segment) -> _hints.Scalar:
"""
Returns squared Euclidean distance between box and a segment.
Time complexity:
``O(1)``
Memory complexity:
``O(1)``
>>> context = get_context()
>>> Box = context.box_cls
>>> Point = context.point_cls
>>> Segment = context.segment_cls
>>> context.box_segment_squared_distance(
... Box(0, 1, 0, 1), Segment(Point(0, 0), Point(1, 1))) == 0
True
>>> context.box_segment_squared_distance(
... Box(0, 1, 0, 1), Segment(Point(2, 0), Point(2, 1))) == 1
True
>>> context.box_segment_squared_distance(
... Box(0, 1, 0, 1), Segment(Point(2, 2), Point(3, 2))) == 2
True
"""
return self._metric.box_segment_squared_metric(
box, segment, self.dot_product, self._segments_intersect,
self.point_cls)
[docs] def contour_box(self, contour: _hints.Contour) -> _hints.Box:
"""
Constructs box from contour.
Time complexity:
``O(vertices_count)``
Memory complexity:
``O(1)``
where ``vertices_count = len(contour.vertices)``.
>>> context = get_context()
>>> Box, Contour, Point = (context.box_cls, context.contour_cls,
... context.point_cls)
>>> (context.contour_box(Contour([Point(0, 0), Point(1, 0),
... Point(1, 1), Point(0, 1)]))
... == Box(0, 1, 0, 1))
True
"""
return _boxed.from_contour(contour, self.box_cls)
[docs] def contour_centroid(self, contour: _hints.Contour) -> _hints.Point:
"""
Constructs centroid of a contour.
Time complexity:
``O(len(contour.vertices))``
Memory complexity:
``O(1)``
>>> context = get_context()
>>> Contour, Point = context.contour_cls, context.point_cls
>>> (context.contour_centroid(Contour([Point(0, 0), Point(2, 0),
... Point(2, 2), Point(0, 2)]))
... == Point(1, 1))
True
"""
return self._centroidal.contour_centroid(contour, self.point_cls,
self.sqrt)
[docs] def contour_length(self, contour: _hints.Contour) -> _hints.Scalar:
"""
Returns Euclidean length of a contour.
Time complexity:
``O(len(contour.vertices))``
Memory complexity:
``O(1)``
>>> context = get_context()
>>> Contour = context.contour_cls
>>> Point = context.point_cls
>>> Segment = context.segment_cls
>>> context.contour_length(Contour([Point(0, 0), Point(3, 0),
... Point(0, 4)])) == 12
True
>>> context.contour_length(Contour([Point(0, 0), Point(1, 0),
... Point(1, 1), Point(0, 1)])) == 4
True
"""
points_squared_distance, sqrt = self.points_squared_distance, self.sqrt
vertices = contour.vertices
return sum(sqrt(points_squared_distance(vertices[index - 1],
vertices[index]))
for index in range(len(vertices)))
[docs] def contour_segments(self, contour: _hints.Contour
) -> _Sequence[_hints.Segment]:
"""
Constructs segments of a contour.
Time complexity:
``O(len(contour.vertices))``
Memory complexity:
``O(1)``
>>> context = get_context()
>>> Contour = context.contour_cls
>>> Point = context.point_cls
>>> Segment = context.segment_cls
>>> (context.contour_segments(Contour([Point(0, 0), Point(2, 0),
... Point(2, 2), Point(0, 2)]))
... == [Segment(Point(0, 2), Point(0, 0)),
... Segment(Point(0, 0), Point(2, 0)),
... Segment(Point(2, 0), Point(2, 2)),
... Segment(Point(2, 2), Point(0, 2))])
True
"""
segment_cls, vertices = self.segment_cls, contour.vertices
return [segment_cls(vertices[index - 1], vertices[index])
for index in range(len(vertices))]
[docs] def contours_box(self, contours: _Sequence[_hints.Contour]) -> _hints.Box:
"""
Constructs box from contours.
Time complexity:
``O(vertices_count)``
Memory complexity:
``O(1)``
where ``vertices_count = sum(len(contour.vertices)\
for contour in contours)``.
>>> context = get_context()
>>> Box = context.box_cls
>>> Contour = context.contour_cls
>>> Point = context.point_cls
>>> (context.contours_box([Contour([Point(0, 0), Point(1, 0),
... Point(1, 1), Point(0, 1)]),
... Contour([Point(1, 1), Point(2, 1),
... Point(2, 2), Point(1, 2)])])
... == Box(0, 2, 0, 2))
True
"""
return _boxed.from_contours(contours, self.box_cls)
[docs] def is_region_convex(self, contour: _hints.Contour) -> bool:
"""
Checks if region (given its contour) is convex.
Time complexity:
``O(len(contour.vertices))``
Memory complexity:
``O(1)``
>>> context = get_context()
>>> Contour = context.contour_cls
>>> Point = context.point_cls
>>> context.is_region_convex(Contour([Point(0, 0), Point(3, 0),
... Point(1, 1), Point(0, 3)]))
False
>>> context.is_region_convex(Contour([Point(0, 0), Point(2, 0),
... Point(2, 2), Point(0, 2)]))
True
"""
vertices = contour.vertices
vertices_count = len(vertices)
if vertices_count == 3:
return True
orienteer = self.angle_orientation
base_orientation = orienteer(vertices[-2], vertices[-1], vertices[0])
# orientation change means that internal angle is greater than 180°
return all(orienteer(vertices[index - 1], vertices[index],
vertices[index + 1]) is base_orientation
for index in range(vertices_count - 1))
[docs] def merged_box(self, first_box: _hints.Box, second_box: _hints.Box
) -> _hints.Box:
"""
Merges two boxes.
Time complexity:
``O(1)``
Memory complexity:
``O(1)``
>>> context = get_context()
>>> Box = context.box_cls
>>> (context.merged_box(Box(0, 1, 0, 1), Box(1, 2, 1, 2))
... == Box(0, 2, 0, 2))
True
"""
return self.box_cls(min(first_box.min_x, second_box.min_x),
max(first_box.max_x, second_box.max_x),
min(first_box.min_y, second_box.min_y),
max(first_box.max_y, second_box.max_y))
[docs] def multipoint_centroid(self, multipoint: _hints.Multipoint
) -> _hints.Point:
"""
Constructs centroid of a multipoint.
Time complexity:
``O(len(multipoint.points))``
Memory complexity:
``O(1)``
>>> context = get_context()
>>> Multipoint = context.multipoint_cls
>>> Point = context.point_cls
>>> context.multipoint_centroid(
... Multipoint([Point(0, 0), Point(2, 0), Point(2, 2),
... Point(0, 2)])) == Point(1, 1)
True
"""
return self._centroidal.multipoint_centroid(multipoint, self.point_cls)
[docs] def multipolygon_centroid(self, multipolygon: _hints.Multipolygon
) -> _hints.Point:
"""
Constructs centroid of a multipolygon.
Time complexity:
``O(len(vertices_count))``
Memory complexity:
``O(1)``
where ``vertices_count = sum(len(polygon.border.vertices)\
+ sum(len(hole.vertices) for hole in polygon.holes)\
for polygon in multipolygon.polygons)``.
>>> context = get_context()
>>> Contour = context.contour_cls
>>> Point = context.point_cls
>>> Polygon = context.polygon_cls
>>> Multipolygon = context.multipolygon_cls
>>> (context.multipolygon_centroid(
... Multipolygon([Polygon(Contour([Point(0, 0), Point(1, 0),
... Point(1, 1), Point(0, 1)]),
... []),
... Polygon(Contour([Point(1, 1), Point(2, 1),
... Point(2, 2), Point(1, 2)]),
... [])]))
... == Point(1, 1))
True
"""
return self._centroidal.multipolygon_centroid(multipolygon,
self.point_cls)
[docs] def multisegment_centroid(self, multisegment: _hints.Multisegment
) -> _hints.Point:
"""
Constructs centroid of a multisegment.
Time complexity:
``O(len(multisegment.segments))``
Memory complexity:
``O(1)``
>>> context = get_context()
>>> Contour = context.contour_cls
>>> Point = context.point_cls
>>> Segment = context.segment_cls
>>> Multisegment = context.multisegment_cls
>>> (context.multisegment_centroid(
... Multisegment([Segment(Point(0, 0), Point(2, 0)),
... Segment(Point(2, 0), Point(2, 2)),
... Segment(Point(0, 2), Point(2, 2)),
... Segment(Point(0, 0), Point(0, 2))]))
... == Point(1, 1))
True
"""
return self._centroidal.multisegment_centroid(
multisegment, self.point_cls, self.sqrt)
[docs] def multisegment_length(self, multisegment: _hints.Multisegment
) -> _hints.Scalar:
"""
Returns Euclidean length of a multisegment.
Time complexity:
``O(len(multisegment.segments))``
Memory complexity:
``O(1)``
>>> context = get_context()
>>> Multisegment = context.multisegment_cls
>>> Point = context.point_cls
>>> Segment = context.segment_cls
>>> context.multisegment_length(
... Multisegment([Segment(Point(0, 0), Point(1, 0)),
... Segment(Point(0, 0), Point(0, 1))])) == 2
True
>>> context.multisegment_length(
... Multisegment([Segment(Point(0, 0), Point(1, 0)),
... Segment(Point(0, 0), Point(3, 4))])) == 6
True
"""
points_squared_distance, sqrt = self.points_squared_distance, self.sqrt
return sum(sqrt(points_squared_distance(segment.start, segment.end))
for segment in multisegment.segments)
[docs] def points_convex_hull(self,
points: _Sequence[_hints.Point]
) -> _Sequence[_hints.Point]:
"""
Constructs convex hull of points.
Time complexity:
``O(points_count * log(points_count))``
Memory complexity:
``O(points_count)``
where ``points_count = len(points)``.
>>> context = get_context()
>>> Point = context.point_cls
>>> (context.points_convex_hull([Point(0, 0), Point(2, 0), Point(2, 2),
... Point(0, 2)])
... == [Point(0, 0), Point(2, 0), Point(2, 2), Point(0, 2)])
True
"""
return _discrete.to_convex_hull(points, self.angle_orientation)
[docs] def points_box(self, points: _Sequence[_hints.Point]) -> _hints.Box:
"""
Constructs box from points.
Time complexity:
``O(len(points))``
Memory complexity:
``O(1)``
>>> context = get_context()
>>> Box, Point = context.box_cls, context.point_cls
>>> (context.points_box([Point(0, 0), Point(2, 0), Point(2, 2),
... Point(0, 2)])
... == Box(0, 2, 0, 2))
True
"""
return _boxed.from_points(points, self.box_cls)
[docs] def polygon_box(self, polygon: _hints.Polygon) -> _hints.Box:
"""
Constructs box from polygon.
Time complexity:
``O(vertices_count)``
Memory complexity:
``O(1)``
where ``vertices_count = len(polygon.border.vertices)``.
>>> context = get_context()
>>> Box, Contour, Point, Polygon = (context.box_cls,
... context.contour_cls,
... context.point_cls,
... context.polygon_cls)
>>> context.polygon_box(
... Polygon(Contour([Point(0, 0), Point(1, 0), Point(1, 1),
... Point(0, 1)]), [])) == Box(0, 1, 0, 1)
True
"""
return _boxed.from_polygon(polygon, self.box_cls)
[docs] def polygon_centroid(self, polygon: _hints.Polygon) -> _hints.Point:
"""
Constructs centroid of a polygon.
Time complexity:
``O(vertices_count)``
Memory complexity:
``O(1)``
where ``vertices_count = len(polygon.border.vertices)\
+ sum(len(hole.vertices) for hole in polygon.holes)``.
>>> context = get_context()
>>> Contour = context.contour_cls
>>> Point = context.point_cls
>>> Polygon = context.polygon_cls
>>> context.polygon_centroid(
... Polygon(Contour([Point(0, 0), Point(4, 0), Point(4, 4),
... Point(0, 4)]),
... [Contour([Point(1, 1), Point(1, 3), Point(3, 3),
... Point(3, 1)])])) == Point(2, 2)
True
"""
return self._centroidal.polygon_centroid(polygon, self.point_cls)
[docs] def polygons_box(self, polygons: _Sequence[_hints.Polygon]) -> _hints.Box:
"""
Constructs box from polygons.
Time complexity:
``O(vertices_count)``
Memory complexity:
``O(1)``
where ``vertices_count = sum(len(polygon.border.vertices)\
for polygon in polygons)``.
>>> context = get_context()
>>> Box, Contour, Point, Polygon = (context.box_cls,
... context.contour_cls,
... context.point_cls,
... context.polygon_cls)
>>> context.polygons_box(
... [Polygon(Contour([Point(0, 0), Point(1, 0), Point(1, 1),
... Point(0, 1)]), []),
... Polygon(Contour([Point(1, 1), Point(2, 1), Point(2, 2),
... Point(1, 2)]), [])]) == Box(0, 2, 0, 2)
True
"""
return _boxed.from_polygons(polygons, self.box_cls)
[docs] def region_centroid(self, contour: _hints.Contour) -> _hints.Point:
"""
Constructs centroid of a region given its contour.
Time complexity:
``O(len(contour.vertices))``
Memory complexity:
``O(1)``
>>> context = get_context()
>>> Contour = context.contour_cls
>>> Point = context.point_cls
>>> (context.region_centroid(Contour([Point(0, 0), Point(2, 0),
... Point(2, 2), Point(0, 2)]))
... == Point(1, 1))
True
"""
return self._centroidal.region_centroid(contour, self.point_cls)
[docs] def replace(self,
*,
box_cls: _Optional[_Type[_hints.Box]] = None,
contour_cls: _Optional[_Type[_hints.Contour]] = None,
empty_cls: _Optional[_Type[_hints.Empty]] = None,
mix_cls: _Optional[_Type[_hints.Mix]] = None,
multipoint_cls: _Optional[_Type[_hints.Multipoint]] = None,
multipolygon_cls: _Optional[_Type[_hints.Multipolygon]] = None,
multisegment_cls: _Optional[_Type[_hints.Multisegment]] = None,
point_cls: _Optional[_Type[_hints.Point]] = None,
polygon_cls: _Optional[_Type[_hints.Polygon]] = None,
segment_cls: _Optional[_Type[_hints.Segment]] = None,
mode: _Optional[Mode] = None,
sqrt: _Optional[_SquareRooter] = None) -> 'Context':
"""
Constructs context from the original one replacing given parameters.
Time complexity:
``O(1)``
Memory complexity:
``O(1)``
>>> context = get_context()
>>> robust_context = context.replace(mode=Mode.ROBUST)
>>> isinstance(robust_context, Context)
True
>>> robust_context.mode is Mode.ROBUST
True
"""
return Context(box_cls=self.box_cls if box_cls is None else box_cls,
contour_cls=(self.contour_cls
if contour_cls is None
else contour_cls),
empty_cls=(self.empty_cls
if empty_cls is None
else empty_cls),
mix_cls=self.mix_cls if mix_cls is None else mix_cls,
multipoint_cls=(self.multipoint_cls
if multipoint_cls is None
else multipoint_cls),
multipolygon_cls=(self.multipolygon_cls
if multipolygon_cls is None
else multipolygon_cls),
multisegment_cls=(self.multisegment_cls
if multisegment_cls is None
else multisegment_cls),
point_cls=(self.point_cls
if point_cls is None
else point_cls),
polygon_cls=(self.polygon_cls
if polygon_cls is None
else polygon_cls),
segment_cls=(self.segment_cls
if segment_cls is None
else segment_cls),
mode=self.mode if mode is None else mode,
sqrt=self.sqrt if sqrt is None else sqrt)
[docs] def rotate_contour(self,
contour: _hints.Contour,
cosine: _hints.Scalar,
sine: _hints.Scalar,
center: _hints.Point) -> _hints.Contour:
"""
Returns contour rotated by given angle around given center.
Time complexity:
``O(len(contour.vertices))``
Memory complexity:
``O(len(contour.vertices))``
>>> context = get_context()
>>> Contour = context.contour_cls
>>> Point = context.point_cls
>>> (context.rotate_contour(
... Contour([Point(0, 0), Point(1, 0), Point(0, 1)]), 1, 0,
... Point(0, 1))
... == Contour([Point(0, 0), Point(1, 0), Point(0, 1)]))
True
>>> (context.rotate_contour(
... Contour([Point(0, 0), Point(1, 0), Point(0, 1)]), 0, 1,
... Point(0, 1))
... == Contour([Point(1, 1), Point(1, 2), Point(0, 1)]))
True
"""
return self._rotation.rotate_translate_contour(
contour, cosine, sine,
*self._rotation.point_to_step(center, cosine, sine),
self.contour_cls, self.point_cls)
[docs] def rotate_contour_around_origin(self,
contour: _hints.Contour,
cosine: _hints.Scalar,
sine: _hints.Scalar) -> _hints.Contour:
"""
Returns contour rotated by given angle around origin.
Time complexity:
``O(len(contour.vertices))``
Memory complexity:
``O(len(contour.vertices))``
>>> context = get_context()
>>> Contour = context.contour_cls
>>> Point = context.point_cls
>>> (context.rotate_contour_around_origin(
... Contour([Point(0, 0), Point(1, 0), Point(0, 1)]), 1, 0)
... == Contour([Point(0, 0), Point(1, 0), Point(0, 1)]))
True
>>> (context.rotate_contour_around_origin(
... Contour([Point(0, 0), Point(1, 0), Point(0, 1)]), 0, 1)
... == Contour([Point(0, 0), Point(0, 1), Point(-1, 0)]))
True
"""
return self._rotation.rotate_contour_around_origin(
contour, cosine, sine, self.contour_cls, self.point_cls)
[docs] def rotate_multipoint(self,
multipoint: _hints.Multipoint,
cosine: _hints.Scalar,
sine: _hints.Scalar,
center: _hints.Point) -> _hints.Multipoint:
"""
Returns multipoint rotated by given angle around given center.
Time complexity:
``O(len(multipoint.points))``
Memory complexity:
``O(len(multipoint.points))``
>>> context = get_context()
>>> Multipoint = context.multipoint_cls
>>> Point = context.point_cls
>>> (context.rotate_multipoint(Multipoint([Point(0, 0), Point(1, 0)]),
... 1, 0, Point(0, 1))
... == Multipoint([Point(0, 0), Point(1, 0)]))
True
>>> (context.rotate_multipoint(Multipoint([Point(0, 0), Point(1, 0)]),
... 0, 1, Point(0, 1))
... == Multipoint([Point(1, 1), Point(1, 2)]))
True
"""
return self._rotation.rotate_translate_multipoint(
multipoint, cosine, sine,
*self._rotation.point_to_step(center, cosine, sine),
self.multipoint_cls, self.point_cls)
[docs] def rotate_multipoint_around_origin(self,
multipoint: _hints.Multipoint,
cosine: _hints.Scalar,
sine: _hints.Scalar
) -> _hints.Multipoint:
"""
Returns multipoint rotated by given angle around origin.
Time complexity:
``O(len(multipoint.points))``
Memory complexity:
``O(len(multipoint.points))``
>>> context = get_context()
>>> Multipoint = context.multipoint_cls
>>> Point = context.point_cls
>>> (context.rotate_multipoint_around_origin(
... Multipoint([Point(0, 0), Point(1, 0)]), 1, 0)
... == Multipoint([Point(0, 0), Point(1, 0)]))
True
>>> (context.rotate_multipoint_around_origin(
... Multipoint([Point(0, 0), Point(1, 0)]), 0, 1)
... == Multipoint([Point(0, 0), Point(0, 1)]))
True
"""
return self._rotation.rotate_multipoint_around_origin(
multipoint, cosine, sine, self.multipoint_cls, self.point_cls)
[docs] def rotate_multipolygon(self,
multipolygon: _hints.Multipolygon,
cosine: _hints.Scalar,
sine: _hints.Scalar,
center: _hints.Point) -> _hints.Multipolygon:
"""
Returns multipolygon rotated by given angle around given center.
Time complexity:
``O(vertices_count)``
Memory complexity:
``O(vertices_count)``
where ``vertices_count = sum(len(polygon.border.vertices)\
+ sum(len(hole.vertices) for hole in polygon.holes)\
for polygon in multipolygon.polygons)``.
>>> context = get_context()
>>> Contour = context.contour_cls
>>> Multipolygon = context.multipolygon_cls
>>> Point = context.point_cls
>>> Polygon = context.polygon_cls
>>> (context.rotate_multipolygon(
... Multipolygon([Polygon(Contour([Point(0, 0), Point(1, 0),
... Point(0, 1)]), [])]),
... 1, 0, Point(0, 1))
... == Multipolygon([Polygon(Contour([Point(0, 0), Point(1, 0),
... Point(0, 1)]), [])]))
True
>>> (context.rotate_multipolygon(
... Multipolygon([Polygon(Contour([Point(0, 0), Point(1, 0),
... Point(0, 1)]), [])]),
... 0, 1, Point(0, 1))
... == Multipolygon([Polygon(Contour([Point(1, 1), Point(1, 2),
... Point(0, 1)]), [])]))
True
"""
return self._rotation.rotate_translate_multipolygon(
multipolygon, cosine, sine,
*self._rotation.point_to_step(center, cosine, sine),
self.contour_cls, self.multipolygon_cls, self.point_cls,
self.polygon_cls)
[docs] def rotate_multipolygon_around_origin(self,
multipolygon: _hints.Multipolygon,
cosine: _hints.Scalar,
sine: _hints.Scalar
) -> _hints.Multipolygon:
"""
Returns multipolygon rotated by given angle around origin.
Time complexity:
``O(vertices_count)``
Memory complexity:
``O(vertices_count)``
where ``vertices_count = sum(len(polygon.border.vertices)\
+ sum(len(hole.vertices) for hole in polygon.holes)\
for polygon in multipolygon.polygons)``.
>>> context = get_context()
>>> Contour = context.contour_cls
>>> Multipolygon = context.multipolygon_cls
>>> Point = context.point_cls
>>> Polygon = context.polygon_cls
>>> (context.rotate_multipolygon_around_origin(
... Multipolygon([Polygon(Contour([Point(0, 0), Point(1, 0),
... Point(0, 1)]), [])]),
... 1, 0)
... == Multipolygon([Polygon(Contour([Point(0, 0), Point(1, 0),
... Point(0, 1)]), [])]))
True
>>> (context.rotate_multipolygon_around_origin(
... Multipolygon([Polygon(Contour([Point(0, 0), Point(1, 0),
... Point(0, 1)]), [])]),
... 0, 1)
... == Multipolygon([Polygon(Contour([Point(0, 0), Point(0, 1),
... Point(-1, 0)]), [])]))
True
"""
return self._rotation.rotate_multipolygon_around_origin(
multipolygon, cosine, sine, self.contour_cls,
self.multipolygon_cls, self.point_cls, self.polygon_cls)
[docs] def rotate_multisegment(self,
multisegment: _hints.Multisegment,
cosine: _hints.Scalar,
sine: _hints.Scalar,
center: _hints.Point) -> _hints.Multisegment:
"""
Returns multisegment rotated by given angle around given center.
Time complexity:
``O(1)``
Memory complexity:
``O(1)``
>>> context = get_context()
>>> Multisegment = context.multisegment_cls
>>> Point = context.point_cls
>>> Segment = context.segment_cls
>>> (context.rotate_multisegment(
... Multisegment([Segment(Point(0, 0), Point(1, 0)),
... Segment(Point(0, 0), Point(0, 1))]), 1, 0,
... Point(0, 1))
... == Multisegment([Segment(Point(0, 0), Point(1, 0)),
... Segment(Point(0, 0), Point(0, 1))]))
True
>>> (context.rotate_multisegment(
... Multisegment([Segment(Point(0, 0), Point(1, 0)),
... Segment(Point(0, 0), Point(0, 1))]), 0, 1,
... Point(0, 1))
... == Multisegment([Segment(Point(1, 1), Point(1,2)),
... Segment(Point(1, 1), Point(0, 1))]))
True
"""
return self._rotation.rotate_translate_multisegment(
multisegment, cosine, sine,
*self._rotation.point_to_step(center, cosine, sine),
self.multisegment_cls, self.point_cls, self.segment_cls)
[docs] def rotate_multisegment_around_origin(self,
multisegment: _hints.Multisegment,
cosine: _hints.Scalar,
sine: _hints.Scalar
) -> _hints.Multisegment:
"""
Returns multisegment rotated by given angle around origin.
Time complexity:
``O(len(multisegment.segments))``
Memory complexity:
``O(len(multisegment.segments))``
>>> context = get_context()
>>> Multisegment = context.multisegment_cls
>>> Point = context.point_cls
>>> Segment = context.segment_cls
>>> (context.rotate_multisegment_around_origin(
... Multisegment([Segment(Point(0, 0), Point(1, 0)),
... Segment(Point(0, 0), Point(0, 1))]), 1, 0)
... == Multisegment([Segment(Point(0, 0), Point(1, 0)),
... Segment(Point(0, 0), Point(0, 1))]))
True
>>> (context.rotate_multisegment_around_origin(
... Multisegment([Segment(Point(0, 0), Point(1, 0)),
... Segment(Point(0, 0), Point(0, 1))]), 0, 1)
... == Multisegment([Segment(Point(0, 0), Point(0, 1)),
... Segment(Point(0, 0), Point(-1, 0))]))
True
"""
return self._rotation.rotate_multisegment_around_origin(
multisegment, cosine, sine, self.multisegment_cls,
self.point_cls, self.segment_cls)
[docs] def rotate_point(self,
point: _hints.Point,
cosine: _hints.Scalar,
sine: _hints.Scalar,
center: _hints.Point) -> _hints.Point:
"""
Returns point rotated by given angle around given center.
Time complexity:
``O(1)``
Memory complexity:
``O(1)``
>>> context = get_context()
>>> Point = context.point_cls
>>> context.rotate_point(Point(1, 0), 1, 0, Point(0, 1)) == Point(1, 0)
True
>>> context.rotate_point(Point(1, 0), 0, 1, Point(0, 1)) == Point(1, 2)
True
"""
return self._rotation.rotate_translate_point(
point, cosine, sine,
*self._rotation.point_to_step(center, cosine, sine),
self.point_cls)
[docs] def rotate_point_around_origin(self,
point: _hints.Point,
cosine: _hints.Scalar,
sine: _hints.Scalar) -> _hints.Point:
"""
Returns point rotated by given angle around origin.
Time complexity:
``O(1)``
Memory complexity:
``O(1)``
>>> context = get_context()
>>> Point = context.point_cls
>>> (context.rotate_point_around_origin(Point(1, 0), 1, 0)
... == Point(1, 0))
True
>>> (context.rotate_point_around_origin(Point(1, 0), 0, 1)
... == Point(0, 1))
True
"""
return self._rotation.rotate_point_around_origin(point, cosine, sine,
self.point_cls)
[docs] def rotate_polygon(self,
polygon: _hints.Polygon,
cosine: _hints.Scalar,
sine: _hints.Scalar,
center: _hints.Point) -> _hints.Polygon:
"""
Returns polygon rotated by given angle around given center.
Time complexity:
``O(vertices_count)``
Memory complexity:
``O(vertices_count)``
where ``vertices_count = len(polygon.border.vertices)\
+ sum(len(hole.vertices) for hole in polygon.holes)``.
>>> context = get_context()
>>> Contour = context.contour_cls
>>> Point = context.point_cls
>>> Polygon = context.polygon_cls
>>> (context.rotate_polygon(
... Polygon(Contour([Point(0, 0), Point(1, 0), Point(0, 1)]), []),
... 1, 0, Point(0, 1))
... == Polygon(Contour([Point(0, 0), Point(1, 0), Point(0, 1)]), []))
True
>>> (context.rotate_polygon(
... Polygon(Contour([Point(0, 0), Point(1, 0), Point(0, 1)]), []),
... 0, 1, Point(0, 1))
... == Polygon(Contour([Point(1, 1), Point(1, 2), Point(0, 1)]), []))
True
"""
return self._rotation.rotate_translate_polygon(
polygon, cosine, sine,
*self._rotation.point_to_step(center, cosine, sine),
self.contour_cls, self.point_cls, self.polygon_cls)
[docs] def rotate_polygon_around_origin(self,
polygon: _hints.Polygon,
cosine: _hints.Scalar,
sine: _hints.Scalar) -> _hints.Polygon:
"""
Returns polygon rotated by given angle around origin.
Time complexity:
``O(vertices_count)``
Memory complexity:
``O(vertices_count)``
where ``vertices_count = len(polygon.border.vertices)\
+ sum(len(hole.vertices) for hole in polygon.holes)``.
>>> context = get_context()
>>> Contour = context.contour_cls
>>> Point = context.point_cls
>>> Polygon = context.polygon_cls
>>> (context.rotate_polygon_around_origin(
... Polygon(Contour([Point(0, 0), Point(1, 0), Point(0, 1)]), []),
... 1, 0)
... == Polygon(Contour([Point(0, 0), Point(1, 0), Point(0, 1)]), []))
True
>>> (context.rotate_polygon_around_origin(
... Polygon(Contour([Point(0, 0), Point(1, 0), Point(0, 1)]), []),
... 0, 1)
... == Polygon(Contour([Point(0, 0), Point(0, 1), Point(-1, 0)]), []))
True
"""
return self._rotation.rotate_polygon_around_origin(
polygon, cosine, sine, self.contour_cls, self.point_cls,
self.polygon_cls)
[docs] def rotate_segment(self,
segment: _hints.Segment,
cosine: _hints.Scalar,
sine: _hints.Scalar,
center: _hints.Point) -> _hints.Segment:
"""
Returns segment rotated by given angle around given center.
Time complexity:
``O(1)``
Memory complexity:
``O(1)``
>>> context = get_context()
>>> Point = context.point_cls
>>> Segment = context.segment_cls
>>> (context.rotate_segment(Segment(Point(0, 0), Point(1, 0)), 1, 0,
... Point(0, 1))
... == Segment(Point(0, 0), Point(1, 0)))
True
>>> (context.rotate_segment(Segment(Point(0, 0), Point(1, 0)), 0, 1,
... Point(0, 1))
... == Segment(Point(1, 1), Point(1, 2)))
True
"""
return self._rotation.rotate_translate_segment(
segment, cosine, sine,
*self._rotation.point_to_step(center, cosine, sine),
self.point_cls, self.segment_cls)
[docs] def rotate_segment_around_origin(self,
segment: _hints.Segment,
cosine: _hints.Scalar,
sine: _hints.Scalar) -> _hints.Segment:
"""
Returns segment rotated by given angle around origin.
Time complexity:
``O(1)``
Memory complexity:
``O(1)``
>>> context = get_context()
>>> Point = context.point_cls
>>> Segment = context.segment_cls
>>> (context.rotate_segment_around_origin(
... Segment(Point(0, 0), Point(1, 0)), 1, 0)
... == Segment(Point(0, 0), Point(1, 0)))
True
>>> (context.rotate_segment_around_origin(
... Segment(Point(0, 0), Point(1, 0)), 0, 1)
... == Segment(Point(0, 0), Point(0, 1)))
True
"""
return self._rotation.rotate_segment_around_origin(
segment, cosine, sine, self.point_cls, self.segment_cls)
[docs] def scale_contour(
self,
contour: _hints.Contour,
factor_x: _hints.Scalar,
factor_y: _hints.Scalar
) -> _Union[_hints.Contour, _hints.Multipoint, _hints.Segment]:
"""
Returns contour scaled by given factor.
Time complexity:
``O(len(contour.vertices))``
Memory complexity:
``O(len(contour.vertices))``
>>> context = get_context()
>>> Contour = context.contour_cls
>>> Multipoint = context.multipoint_cls
>>> Point = context.point_cls
>>> Segment = context.segment_cls
>>> (context.scale_contour(Contour([Point(0, 0), Point(1, 0),
... Point(0, 1)]), 0, 0)
... == Multipoint([Point(0, 0)]))
True
>>> (context.scale_contour(Contour([Point(0, 0), Point(1, 0),
... Point(0, 1)]), 1, 0)
... == Segment(Point(0, 0), Point(1, 0)))
True
>>> (context.scale_contour(Contour([Point(0, 0), Point(1, 0),
... Point(0, 1)]), 0, 1)
... == Segment(Point(0, 0), Point(0, 1)))
True
>>> (context.scale_contour(Contour([Point(0, 0), Point(1, 0),
... Point(0, 1)]), 1, 1)
... == Contour([Point(0, 0), Point(1, 0), Point(0, 1)]))
True
"""
return self._scaling.scale_contour(
contour, factor_x, factor_y, self.contour_cls,
self.multipoint_cls, self.point_cls, self.segment_cls)
[docs] def scale_multipoint(self,
multipoint: _hints.Multipoint,
factor_x: _hints.Scalar,
factor_y: _hints.Scalar) -> _hints.Multipoint:
"""
Returns multipoint scaled by given factor.
Time complexity:
``O(len(multipoint.points))``
Memory complexity:
``O(len(multipoint.points))``
>>> context = get_context()
>>> Multipoint = context.multipoint_cls
>>> Point = context.point_cls
>>> (context.scale_multipoint(Multipoint([Point(0, 0), Point(1, 1)]),
... 0, 0)
... == Multipoint([Point(0, 0)]))
True
>>> (context.scale_multipoint(Multipoint([Point(0, 0), Point(1, 1)]),
... 1, 0)
... == Multipoint([Point(0, 0), Point(1, 0)]))
True
>>> (context.scale_multipoint(Multipoint([Point(0, 0), Point(1, 1)]),
... 0, 1)
... == Multipoint([Point(0, 0), Point(0, 1)]))
True
>>> (context.scale_multipoint(Multipoint([Point(0, 0), Point(1, 1)]),
... 1, 1)
... == Multipoint([Point(0, 0), Point(1, 1)]))
True
"""
return self._scaling.scale_multipoint(multipoint, factor_x, factor_y,
self.multipoint_cls,
self.point_cls)
[docs] def scale_multipolygon(
self,
multipolygon: _hints.Multipolygon,
factor_x: _hints.Scalar,
factor_y: _hints.Scalar
) -> _Union[_hints.Multipoint, _hints.Multipolygon, _hints.Multisegment]:
"""
Returns multipolygon scaled by given factor.
Time complexity:
``O(vertices_count)``
Memory complexity:
``O(vertices_count)``
where ``vertices_count = sum(len(polygon.border.vertices)\
+ sum(len(hole.vertices) for hole in polygon.holes)\
for polygon in multipolygon.polygons)``.
>>> context = get_context()
>>> 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
>>> (context.scale_multipolygon(
... Multipolygon([Polygon(Contour([Point(0, 0), Point(1, 0),
... Point(0, 1)]), []),
... Polygon(Contour([Point(1, 1), Point(2, 1),
... Point(1, 2)]), [])]), 0, 0)
... == Multipoint([Point(0, 0)]))
True
>>> (context.scale_multipolygon(
... Multipolygon([Polygon(Contour([Point(0, 0), Point(1, 0),
... Point(0, 1)]), []),
... Polygon(Contour([Point(1, 1), Point(2, 1),
... Point(1, 2)]), [])]), 1, 0)
... == Multisegment([Segment(Point(0, 0), Point(1, 0)),
... Segment(Point(1, 0), Point(2, 0))]))
True
>>> (context.scale_multipolygon(
... Multipolygon([Polygon(Contour([Point(0, 0), Point(1, 0),
... Point(0, 1)]), []),
... Polygon(Contour([Point(1, 1), Point(2, 1),
... Point(1, 2)]), [])]), 0, 1)
... == Multisegment([Segment(Point(0, 0), Point(0, 1)),
... Segment(Point(0, 1), Point(0, 2))]))
True
>>> (context.scale_multipolygon(
... Multipolygon([Polygon(Contour([Point(0, 0), Point(1, 0),
... Point(0, 1)]), []),
... Polygon(Contour([Point(1, 1), Point(2, 1),
... Point(1, 2)]), [])]), 1, 1)
... == Multipolygon([Polygon(Contour([Point(0, 0), Point(1, 0),
... Point(0, 1)]), []),
... Polygon(Contour([Point(1, 1), Point(2, 1),
... Point(1, 2)]), [])]))
True
"""
return self._scaling.scale_multipolygon(
multipolygon, factor_x, factor_y, self.contour_cls,
self.multipoint_cls, self.multipolygon_cls,
self.multisegment_cls, self.point_cls, self.polygon_cls,
self.segment_cls)
[docs] def scale_multisegment(
self,
multisegment: _hints.Multisegment,
factor_x: _hints.Scalar,
factor_y: _hints.Scalar
) -> _Union[_hints.Mix, _hints.Multipoint, _hints.Multisegment]:
"""
Returns multisegment scaled by given factor.
Time complexity:
``O(len(multisegment.segments))``
Memory complexity:
``O(len(multisegment.segments))``
>>> 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
>>> (context.scale_multisegment(
... Multisegment([Segment(Point(0, 0), Point(1, 0)),
... Segment(Point(0, 0), Point(0, 1))]), 0, 0)
... == Multipoint([Point(0, 0)]))
True
>>> (context.scale_multisegment(
... Multisegment([Segment(Point(0, 0), Point(1, 0)),
... Segment(Point(0, 0), Point(0, 1))]), 1, 0)
... == Mix(Multipoint([Point(0, 0)]),
... Segment(Point(0, 0), Point(1, 0)), EMPTY))
True
>>> (context.scale_multisegment(
... Multisegment([Segment(Point(0, 0), Point(1, 0)),
... Segment(Point(0, 0), Point(0, 1))]), 0, 1)
... == Mix(Multipoint([Point(0, 0)]),
... Segment(Point(0, 0), Point(0, 1)), EMPTY))
True
>>> (context.scale_multisegment(
... Multisegment([Segment(Point(0, 0), Point(1, 0)),
... Segment(Point(0, 0), Point(0, 1))]), 1, 1)
... == Multisegment([Segment(Point(0, 0), Point(1, 0)),
... Segment(Point(0, 0), Point(0, 1))]))
True
"""
return self._scaling.scale_multisegment(
multisegment, factor_x, factor_y, self.empty, self.mix_cls,
self.multipoint_cls, self.multisegment_cls, self.point_cls,
self.segment_cls)
[docs] def scale_point(self,
point: _hints.Point,
factor_x: _hints.Scalar,
factor_y: _hints.Scalar) -> _hints.Point:
"""
Returns point scaled by given factor.
Time complexity:
``O(1)``
Memory complexity:
``O(1)``
>>> context = get_context()
>>> Point = context.point_cls
>>> context.scale_point(Point(1, 1), 0, 0) == Point(0, 0)
True
>>> context.scale_point(Point(1, 1), 1, 0) == Point(1, 0)
True
>>> context.scale_point(Point(1, 1), 0, 1) == Point(0, 1)
True
>>> context.scale_point(Point(1, 1), 1, 1) == Point(1, 1)
True
"""
return self._scaling.scale_point(point, factor_x, factor_y,
self.point_cls)
[docs] def scale_polygon(
self,
polygon: _hints.Polygon,
factor_x: _hints.Scalar,
factor_y: _hints.Scalar
) -> _Union[_hints.Multipoint, _hints.Polygon, _hints.Segment]:
"""
Returns polygon scaled by given factor.
Time complexity:
``O(vertices_count)``
Memory complexity:
``O(vertices_count)``
where ``vertices_count = len(polygon.border.vertices)\
+ sum(len(hole.vertices) for hole in polygon.holes)``.
>>> context = get_context()
>>> Contour = context.contour_cls
>>> Multipoint = context.multipoint_cls
>>> Point = context.point_cls
>>> Polygon = context.polygon_cls
>>> Segment = context.segment_cls
>>> (context.scale_polygon(
... Polygon(Contour([Point(0, 0), Point(1, 0), Point(0, 1)]), []),
... 0, 0)
... == Multipoint([Point(0, 0)]))
True
>>> (context.scale_polygon(
... Polygon(Contour([Point(0, 0), Point(1, 0), Point(0, 1)]), []),
... 1, 0)
... == Segment(Point(0, 0), Point(1, 0)))
True
>>> (context.scale_polygon(
... Polygon(Contour([Point(0, 0), Point(1, 0), Point(0, 1)]), []),
... 0, 1)
... == Segment(Point(0, 0), Point(0, 1)))
True
>>> (context.scale_polygon(
... Polygon(Contour([Point(0, 0), Point(1, 0), Point(0, 1)]), []),
... 1, 1)
... == Polygon(Contour([Point(0, 0), Point(1, 0), Point(0, 1)]), []))
True
"""
return self._scaling.scale_polygon(
polygon, factor_x, factor_y, self.contour_cls,
self.multipoint_cls, self.point_cls, self.polygon_cls,
self.segment_cls)
[docs] def scale_segment(self,
segment: _hints.Segment,
factor_x: _hints.Scalar,
factor_y: _hints.Scalar
) -> _Union[_hints.Multipoint, _hints.Segment]:
"""
Returns segment scaled by given factor.
Time complexity:
``O(1)``
Memory complexity:
``O(1)``
>>> context = get_context()
>>> Multipoint = context.multipoint_cls
>>> Point = context.point_cls
>>> Segment = context.segment_cls
>>> (context.scale_segment(Segment(Point(0, 0), Point(1, 1)), 0, 0)
... == Multipoint([Point(0, 0)]))
True
>>> (context.scale_segment(Segment(Point(0, 0), Point(1, 1)), 1, 0)
... == Segment(Point(0, 0), Point(1, 0)))
True
>>> (context.scale_segment(Segment(Point(0, 0), Point(1, 1)), 0, 1)
... == Segment(Point(0, 0), Point(0, 1)))
True
>>> (context.scale_segment(Segment(Point(0, 0), Point(1, 1)), 1, 1)
... == Segment(Point(0, 0), Point(1, 1)))
True
"""
return self._scaling.scale_segment(
segment, factor_x, factor_y, self.multipoint_cls,
self.point_cls, self.segment_cls)
[docs] def segment_box(self, segment: _hints.Segment) -> _hints.Box:
"""
Constructs box from segment.
Time complexity:
``O(1)``
Memory complexity:
``O(1)``
>>> context = get_context()
>>> Box, Point, Segment = (context.box_cls, context.point_cls,
... context.segment_cls)
>>> (context.segment_box(Segment(Point(0, 1), Point(2, 3)))
... == Box(0, 2, 1, 3))
True
"""
return _boxed.from_segment(segment, self.box_cls)
[docs] def segment_centroid(self, segment: _hints.Segment) -> _hints.Point:
"""
Constructs centroid of a segment.
Time complexity:
``O(1)``
Memory complexity:
``O(1)``
>>> context = get_context()
>>> Point, Segment = context.point_cls, context.segment_cls
>>> (context.segment_centroid(Segment(Point(0, 1), Point(2, 3)))
... == Point(1, 2))
True
"""
return self._centroidal.segment_centroid(segment, self.point_cls)
[docs] def segment_contains_point(self,
segment: _hints.Segment,
point: _hints.Point) -> bool:
"""
Checks if a segment contains given point.
Time complexity:
``O(1)``
Memory complexity:
``O(1)``
>>> context = get_context()
>>> Point = context.point_cls
>>> Segment = context.segment_cls
>>> context.segment_contains_point(Segment(Point(0, 0), Point(2, 0)),
... Point(0, 0))
True
>>> context.segment_contains_point(Segment(Point(0, 0), Point(2, 0)),
... Point(0, 2))
False
>>> context.segment_contains_point(Segment(Point(0, 0), Point(2, 0)),
... Point(1, 0))
True
>>> context.segment_contains_point(Segment(Point(0, 0), Point(2, 0)),
... Point(1, 1))
False
>>> context.segment_contains_point(Segment(Point(0, 0), Point(2, 0)),
... Point(2, 0))
True
>>> context.segment_contains_point(Segment(Point(0, 0), Point(2, 0)),
... Point(3, 0))
False
"""
return self._segment.containment_checker(segment.start, segment.end,
point, self.angle_orientation)
[docs] def segment_length(self, segment: _hints.Segment) -> _hints.Scalar:
"""
Returns Euclidean length of a segment.
Time complexity:
``O(1)``
Memory complexity:
``O(1)``
>>> context = get_context()
>>> Point = context.point_cls
>>> Segment = context.segment_cls
>>> context.segment_length(Segment(Point(0, 0), Point(1, 0))) == 1
True
>>> context.segment_length(Segment(Point(0, 0), Point(0, 1))) == 1
True
>>> context.segment_length(Segment(Point(0, 0), Point(3, 4))) == 5
True
"""
return self.sqrt(self.points_squared_distance(segment.start,
segment.end))
[docs] def segment_point_squared_distance(self,
segment: _hints.Segment,
point: _hints.Point) -> _hints.Scalar:
"""
Returns squared Euclidean distance between segment and a point.
Time complexity:
``O(1)``
Memory complexity:
``O(1)``
>>> context = get_context()
>>> Point = context.point_cls
>>> Segment = context.segment_cls
>>> context.segment_point_squared_distance(
... Segment(Point(0, 0), Point(1, 0)), Point(0, 0)) == 0
True
>>> context.segment_point_squared_distance(
... Segment(Point(0, 0), Point(1, 0)), Point(0, 1)) == 1
True
>>> context.segment_point_squared_distance(
... Segment(Point(0, 0), Point(1, 0)), Point(2, 1)) == 2
True
"""
return self._metric.segment_point_squared_metric(
segment.start, segment.end, point, self.dot_product)
[docs] def segments_box(self, segments: _Sequence[_hints.Segment]) -> _hints.Box:
"""
Constructs box from segments.
Time complexity:
``O(len(segments))``
Memory complexity:
``O(1)``
>>> context = get_context()
>>> Box, Point, Segment = (context.box_cls, context.point_cls,
... context.segment_cls)
>>> (context.segments_box([Segment(Point(0, 0), Point(1, 1)),
... Segment(Point(1, 1), Point(2, 2))])
... == Box(0, 2, 0, 2))
True
"""
return _boxed.from_segments(segments, self.box_cls)
[docs] def segments_intersection(self,
first: _hints.Segment,
second: _hints.Segment) -> _hints.Point:
"""
Returns intersection point of two segments.
Time complexity:
``O(1)``
Memory complexity:
``O(1)``
>>> context = get_context()
>>> Point = context.point_cls
>>> Segment = context.segment_cls
>>> (context.segments_intersection(Segment(Point(0, 0), Point(2, 0)),
... Segment(Point(0, 0), Point(0, 1)))
... == Point(0, 0))
True
>>> (context.segments_intersection(Segment(Point(0, 0), Point(2, 0)),
... Segment(Point(1, 0), Point(1, 1)))
... == Point(1, 0))
True
>>> (context.segments_intersection(Segment(Point(0, 0), Point(2, 0)),
... Segment(Point(2, 0), Point(3, 0)))
... == Point(2, 0))
True
"""
return self._segment.intersector(first.start, first.end, second.start,
second.end, self.point_cls,
self._segment_contains_point)
[docs] def segments_relation(self,
test: _hints.Segment,
goal: _hints.Segment) -> Relation:
"""
Returns relation between two segments.
Time complexity:
``O(1)``
Memory complexity:
``O(1)``
>>> context = get_context()
>>> Point = context.point_cls
>>> Segment = context.segment_cls
>>> (context.segments_relation(Segment(Point(0, 0), Point(2, 2)),
... Segment(Point(1, 0), Point(2, 0)))
... is Relation.DISJOINT)
True
>>> (context.segments_relation(Segment(Point(0, 0), Point(2, 2)),
... Segment(Point(0, 0), Point(2, 0)))
... is Relation.TOUCH)
True
>>> (context.segments_relation(Segment(Point(0, 0), Point(2, 2)),
... Segment(Point(2, 0), Point(0, 2)))
... is Relation.CROSS)
True
>>> (context.segments_relation(Segment(Point(0, 0), Point(2, 2)),
... Segment(Point(0, 0), Point(1, 1)))
... is Relation.COMPOSITE)
True
>>> (context.segments_relation(Segment(Point(0, 0), Point(2, 2)),
... Segment(Point(0, 0), Point(2, 2)))
... is Relation.EQUAL)
True
>>> (context.segments_relation(Segment(Point(0, 0), Point(2, 2)),
... Segment(Point(0, 0), Point(3, 3)))
... is Relation.COMPONENT)
True
>>> (context.segments_relation(Segment(Point(0, 0), Point(2, 2)),
... Segment(Point(1, 1), Point(3, 3)))
... is Relation.OVERLAP)
True
"""
return self._segment.relater(test.start, test.end, goal.start,
goal.end, self.angle_orientation)
[docs] def segments_squared_distance(self,
first: _hints.Segment,
second: _hints.Segment) -> _hints.Scalar:
"""
Returns squared Euclidean distance between two segments.
Time complexity:
``O(1)``
Memory complexity:
``O(1)``
>>> context = get_context()
>>> Point = context.point_cls
>>> Segment = context.segment_cls
>>> context.segments_squared_distance(
... Segment(Point(0, 0), Point(1, 0)),
... Segment(Point(0, 0), Point(0, 1))) == 0
True
>>> context.segments_squared_distance(
... Segment(Point(0, 0), Point(1, 0)),
... Segment(Point(0, 1), Point(1, 1))) == 1
True
>>> context.segments_squared_distance(
... Segment(Point(0, 0), Point(1, 0)),
... Segment(Point(2, 1), Point(2, 2))) == 2
True
"""
return self._metric.segment_segment_squared_metric(
first.start, first.end, second.start, second.end,
self.dot_product, self._segments_intersect)
[docs] def translate_contour(self,
contour: _hints.Contour,
step_x: _hints.Scalar,
step_y: _hints.Scalar) -> _hints.Contour:
"""
Returns contour translated by given step.
Time complexity:
``O(len(contour.vertices))``
Memory complexity:
``O(len(contour.vertices))``
>>> context = get_context()
>>> Contour = context.contour_cls
>>> Point = context.point_cls
>>> Segment = context.segment_cls
>>> (context.translate_contour(Contour([Point(0, 0), Point(1, 0),
... Point(0, 1)]), 0, 0)
... == Contour([Point(0, 0), Point(1, 0), Point(0, 1)]))
True
>>> (context.translate_contour(Contour([Point(0, 0), Point(1, 0),
... Point(0, 1)]), 1, 0)
... == Contour([Point(1, 0), Point(2, 0), Point(1, 1)]))
True
>>> (context.translate_contour(Contour([Point(0, 0), Point(1, 0),
... Point(0, 1)]), 0, 1)
... == Contour([Point(0, 1), Point(1, 1), Point(0, 2)]))
True
>>> (context.translate_contour(Contour([Point(0, 0), Point(1, 0),
... Point(0, 1)]), 1, 1)
... == Contour([Point(1, 1), Point(2, 1), Point(1, 2)]))
True
"""
return self._translation.translate_contour(
contour, step_x, step_y, self.contour_cls, self.point_cls)
[docs] def translate_multipoint(self,
multipoint: _hints.Multipoint,
step_x: _hints.Scalar,
step_y: _hints.Scalar) -> _hints.Multipoint:
"""
Returns multipoint translated by given step.
Time complexity:
``O(len(multipoint.points))``
Memory complexity:
``O(len(multipoint.points))``
>>> context = get_context()
>>> Multipoint = context.multipoint_cls
>>> Point = context.point_cls
>>> (context.translate_multipoint(Multipoint([Point(0, 0),
... Point(1, 0)]), 0, 0)
... == Multipoint([Point(0, 0), Point(1, 0)]))
True
>>> (context.translate_multipoint(Multipoint([Point(0, 0),
... Point(1, 0)]), 1, 0)
... == Multipoint([Point(1, 0), Point(2, 0)]))
True
>>> (context.translate_multipoint(Multipoint([Point(0, 0),
... Point(1, 0)]), 0, 1)
... == Multipoint([Point(0, 1), Point(1, 1)]))
True
>>> (context.translate_multipoint(Multipoint([Point(0, 0),
... Point(1, 0)]), 1, 1)
... == Multipoint([Point(1, 1), Point(2, 1)]))
True
"""
return self._translation.translate_multipoint(
multipoint, step_x, step_y, self.multipoint_cls,
self.point_cls)
[docs] def translate_multipolygon(self,
multipolygon: _hints.Multipolygon,
step_x: _hints.Scalar,
step_y: _hints.Scalar) -> _hints.Multipolygon:
"""
Returns multipolygon translated by given step.
Time complexity:
``O(vertices_count)``
Memory complexity:
``O(vertices_count)``
where ``vertices_count = sum(len(polygon.border.vertices)\
+ sum(len(hole.vertices) for hole in polygon.holes)\
for polygon in multipolygon.polygons)``.
>>> context = get_context()
>>> Contour = context.contour_cls
>>> Multipolygon = context.multipolygon_cls
>>> Point = context.point_cls
>>> Polygon = context.polygon_cls
>>> (context.translate_multipolygon(
... Multipolygon([Polygon(Contour([Point(0, 0), Point(1, 0),
... Point(0, 1)]), []),
... Polygon(Contour([Point(1, 1), Point(2, 1),
... Point(1, 2)]), [])]), 0, 0)
... == Multipolygon([Polygon(Contour([Point(0, 0), Point(1, 0),
... Point(0, 1)]), []),
... Polygon(Contour([Point(1, 1), Point(2, 1),
... Point(1, 2)]), [])]))
True
>>> (context.translate_multipolygon(
... Multipolygon([Polygon(Contour([Point(0, 0), Point(1, 0),
... Point(0, 1)]), []),
... Polygon(Contour([Point(1, 1), Point(2, 1),
... Point(1, 2)]), [])]), 1, 0)
... == Multipolygon([Polygon(Contour([Point(1, 0), Point(2, 0),
... Point(1, 1)]), []),
... Polygon(Contour([Point(2, 1), Point(3, 1),
... Point(2, 2)]), [])]))
True
>>> (context.translate_multipolygon(
... Multipolygon([Polygon(Contour([Point(0, 0), Point(1, 0),
... Point(0, 1)]), []),
... Polygon(Contour([Point(1, 1), Point(2, 1),
... Point(1, 2)]), [])]), 0, 1)
... == Multipolygon([Polygon(Contour([Point(0, 1), Point(1, 1),
... Point(0, 2)]), []),
... Polygon(Contour([Point(1, 2), Point(2, 2),
... Point(1, 3)]), [])]))
True
>>> (context.translate_multipolygon(
... Multipolygon([Polygon(Contour([Point(0, 0), Point(1, 0),
... Point(0, 1)]), []),
... Polygon(Contour([Point(1, 1), Point(2, 1),
... Point(1, 2)]), [])]), 1, 1)
... == Multipolygon([Polygon(Contour([Point(1, 1), Point(2, 1),
... Point(1, 2)]), []),
... Polygon(Contour([Point(2, 2), Point(3, 2),
... Point(2, 3)]), [])]))
True
"""
return self._translation.translate_multipolygon(
multipolygon, step_x, step_y, self.contour_cls,
self.multipolygon_cls, self.point_cls, self.polygon_cls)
[docs] def translate_multisegment(self,
multisegment: _hints.Multisegment,
step_x: _hints.Scalar,
step_y: _hints.Scalar) -> _hints.Multisegment:
"""
Returns multisegment translated by given step.
Time complexity:
``O(len(multisegment.segments))``
Memory complexity:
``O(len(multisegment.segments))``
>>> context = get_context()
>>> Multisegment = context.multisegment_cls
>>> Point = context.point_cls
>>> Segment = context.segment_cls
>>> (context.translate_multisegment(
... Multisegment([Segment(Point(0, 0), Point(1, 0)),
... Segment(Point(0, 0), Point(0, 1))]), 0, 0)
... == Multisegment([Segment(Point(0, 0), Point(1, 0)),
... Segment(Point(0, 0), Point(0, 1))]))
True
>>> (context.translate_multisegment(
... Multisegment([Segment(Point(0, 0), Point(1, 0)),
... Segment(Point(0, 0), Point(0, 1))]), 1, 0)
... == Multisegment([Segment(Point(1, 0), Point(2, 0)),
... Segment(Point(1, 0), Point(1, 1))]))
True
>>> (context.translate_multisegment(
... Multisegment([Segment(Point(0, 0), Point(1, 0)),
... Segment(Point(0, 0), Point(0, 1))]), 0, 1)
... == Multisegment([Segment(Point(0, 1), Point(1, 1)),
... Segment(Point(0, 1), Point(0, 2))]))
True
>>> (context.translate_multisegment(
... Multisegment([Segment(Point(0, 0), Point(1, 0)),
... Segment(Point(0, 0), Point(0, 1))]), 1, 1)
... == Multisegment([Segment(Point(1, 1), Point(2, 1)),
... Segment(Point(1, 1), Point(1, 2))]))
True
"""
return self._translation.translate_multisegment(
multisegment, step_x, step_y, self.multisegment_cls,
self.point_cls, self.segment_cls)
[docs] def translate_point(self,
point: _hints.Point,
step_x: _hints.Scalar,
step_y: _hints.Scalar) -> _hints.Point:
"""
Returns point translated by given step.
Time complexity:
``O(1)``
Memory complexity:
``O(1)``
>>> context = get_context()
>>> Point = context.point_cls
>>> context.translate_point(Point(0, 0), 0, 0) == Point(0, 0)
True
>>> context.translate_point(Point(0, 0), 1, 0) == Point(1, 0)
True
>>> context.translate_point(Point(0, 0), 0, 1) == Point(0, 1)
True
>>> context.translate_point(Point(0, 0), 1, 1) == Point(1, 1)
True
"""
return self._translation.translate_point(point, step_x, step_y,
self.point_cls)
[docs] def translate_polygon(self,
polygon: _hints.Polygon,
step_x: _hints.Scalar,
step_y: _hints.Scalar) -> _hints.Polygon:
"""
Returns polygon translated by given step.
Time complexity:
``O(vertices_count)``
Memory complexity:
``O(vertices_count)``
where ``vertices_count = len(polygon.border.vertices)\
+ sum(len(hole.vertices) for hole in polygon.holes)``.
>>> context = get_context()
>>> Contour = context.contour_cls
>>> Point = context.point_cls
>>> Polygon = context.polygon_cls
>>> (context.translate_polygon(
... Polygon(Contour([Point(0, 0), Point(1, 0), Point(0, 1)]), []),
... 0, 0)
... == Polygon(Contour([Point(0, 0), Point(1, 0), Point(0, 1)]), []))
True
>>> (context.translate_polygon(
... Polygon(Contour([Point(0, 0), Point(1, 0), Point(0, 1)]), []),
... 1, 0)
... == Polygon(Contour([Point(1, 0), Point(2, 0), Point(1, 1)]), []))
True
>>> (context.translate_polygon(
... Polygon(Contour([Point(0, 0), Point(1, 0), Point(0, 1)]), []),
... 0, 1)
... == Polygon(Contour([Point(0, 1), Point(1, 1), Point(0, 2)]), []))
True
>>> (context.translate_polygon(
... Polygon(Contour([Point(0, 0), Point(1, 0), Point(0, 1)]), []),
... 1, 1)
... == Polygon(Contour([Point(1, 1), Point(2, 1), Point(1, 2)]), []))
True
"""
return self._translation.translate_polygon(
polygon, step_x, step_y, self.contour_cls, self.point_cls,
self.polygon_cls)
[docs] def translate_segment(self,
segment: _hints.Segment,
step_x: _hints.Scalar,
step_y: _hints.Scalar) -> _hints.Segment:
"""
Returns segment translated by given step.
Time complexity:
``O(1)``
Memory complexity:
``O(1)``
>>> context = get_context()
>>> Point = context.point_cls
>>> Segment = context.segment_cls
>>> (context.translate_segment(Segment(Point(0, 0), Point(1, 0)), 0, 0)
... == Segment(Point(0, 0), Point(1, 0)))
True
>>> (context.translate_segment(Segment(Point(0, 0), Point(1, 0)), 1, 0)
... == Segment(Point(1, 0), Point(2, 0)))
True
>>> (context.translate_segment(Segment(Point(0, 0), Point(1, 0)), 0, 1)
... == Segment(Point(0, 1), Point(1, 1)))
True
>>> (context.translate_segment(Segment(Point(0, 0), Point(1, 0)), 1, 1)
... == Segment(Point(1, 1), Point(2, 1)))
True
"""
return self._translation.translate_segment(
segment, step_x, step_y, self.point_cls, self.segment_cls)
def _segment_contains_point(self,
start: _hints.Point,
end: _hints.Point,
point: _hints.Point) -> bool:
return self._segment.containment_checker(start, end, point,
self.angle_orientation)
def _segments_intersect(self,
first_start: _hints.Point,
first_end: _hints.Point,
second_start: _hints.Point,
second_end: _hints.Point) -> bool:
return self._segment.collision_detector(first_start, first_end,
second_start, second_end,
self.angle_orientation)
_context = _ContextVar('context',
default=Context())
[docs]def get_context() -> Context:
"""Returns current context."""
return _context.get()
[docs]def set_context(context: Context) -> None:
"""Sets current context."""
assert isinstance(context, Context), ('Expected "{expected}" instance, '
'but got "{actual}".'
.format(expected=Context,
actual=context))
_context.set(context)