from __future__ import annotations
from collections.abc import Callable as _Callable, Sequence as _Sequence
from typing import Any as _Any, Generic as _Generic, final as _final
from reprit import serializers as _serializers
from reprit.base import generate_repr as _generate_repr
from typing_extensions import Self as _Self
from ._core import (
angular as _angular,
boxed as _boxed,
centroidal as _centroidal,
circular as _circular,
discrete as _discrete,
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.enums import (
Kind as _Kind,
Location as _Location,
Orientation as _Orientation,
Relation as _Relation,
)
from ._core.hints import (
HasRepr as _HasRepr,
QuaternaryPointFunction as _QuaternaryPointFunction,
ScalarFactory as _ScalarFactory,
ScalarT as _ScalarT,
SquareRooter as _SquareRooter,
)
from .hints import (
Box as _Box,
Contour as _Contour,
Empty as _Empty,
Linear as _Linear,
Mix as _Mix,
Multipoint as _Multipoint,
Multipolygon as _Multipolygon,
Multisegment as _Multisegment,
Point as _Point,
Polygon as _Polygon,
Segment as _Segment,
Shaped as _Shaped,
)
[docs]
@_final
class Context(_HasRepr, _Generic[_ScalarT]):
"""Represents common language for computational geometry."""
@property
def box_cls(self, /) -> type[_Box[_ScalarT]]:
"""Returns type of boxes."""
return self._box_cls
@property
def contour_cls(self, /) -> type[_Contour[_ScalarT]]:
"""Returns type of contours."""
return self._contour_cls
@property
def coordinate_factory(self, /) -> _Callable[[int], _ScalarT]:
"""Returns coordinate factory."""
return self._coordinate_factory
@property
def cross_product(self, /) -> _QuaternaryPointFunction[_ScalarT, _ScalarT]:
"""
Returns cross product of the segments.
Time complexity:
``O(1)``
Memory complexity:
``O(1)``
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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_context.cross_product
@property
def dot_product(self, /) -> _QuaternaryPointFunction[_ScalarT, _ScalarT]:
"""
Returns dot product of the segments.
Time complexity:
``O(1)``
Memory complexity:
``O(1)``
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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_context.dot_product
@property
def empty(self, /) -> _Empty[_ScalarT]:
"""Returns an empty geometry."""
return self._empty
@property
def empty_cls(self, /) -> type[_Empty[_ScalarT]]:
"""Returns type of empty geometries."""
return self._empty_cls
@property
def mix_cls(self, /) -> type[_Mix[_ScalarT]]:
"""Returns type of mixes."""
return self._mix_cls
@property
def multipoint_cls(self, /) -> type[_Multipoint[_ScalarT]]:
"""Returns type of multipoints."""
return self._multipoint_cls
@property
def multipolygon_cls(self, /) -> type[_Multipolygon[_ScalarT]]:
"""Returns type of multipolygons."""
return self._multipolygon_cls
@property
def multisegment_cls(self, /) -> type[_Multisegment[_ScalarT]]:
"""Returns type of multisegments."""
return self._multisegment_cls
@property
def origin(self, /) -> _Point[_ScalarT]:
"""Returns origin."""
return self._origin
@property
def point_cls(self, /) -> type[_Point[_ScalarT]]:
"""Returns type of points."""
return self._point_cls
@property
def points_squared_distance(self, /) -> _metric.PointPointMetric[_ScalarT]:
"""
Returns squared Euclidean distance between two points.
Time complexity:
``O(1)``
Memory complexity:
``O(1)``
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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_context.point_point_squared_metric
@property
def polygon_cls(self, /) -> type[_Polygon[_ScalarT]]:
"""Returns type of polygons."""
return self._polygon_cls
@property
def segment_cls(self, /) -> type[_Segment[_ScalarT]]:
"""Returns type of segments."""
return self._segment_cls
@property
def sqrt(self, /) -> _SquareRooter[_ScalarT]:
"""Returns function for computing square root."""
return self._sqrt
@property
def zero(self, /) -> _ScalarT:
"""Returns zero."""
return self._zero
[docs]
def angle_kind(
self,
vertex: _Point[_ScalarT],
first_ray_point: _Point[_ScalarT],
second_ray_point: _Point[_ScalarT],
/,
) -> _Kind:
"""
Returns function for computing angle kind.
Time complexity:
``O(1)``
Memory complexity:
``O(1)``
>>> from ground.enums import Kind
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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_context.kind(
vertex,
first_ray_point,
second_ray_point,
self._vector_context.dot_product,
self._zero,
)
[docs]
def angle_orientation(
self,
vertex: _Point[_ScalarT],
first_ray_point: _Point[_ScalarT],
second_ray_point: _Point[_ScalarT],
/,
) -> _Orientation:
"""
Returns function for computing angle orientation.
Time complexity:
``O(1)``
Memory complexity:
``O(1)``
>>> from ground.enums import Orientation
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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_context.orientation(
vertex,
first_ray_point,
second_ray_point,
self._vector_context.cross_product,
self._zero,
)
[docs]
def box_point_squared_distance(
self, box: _Box[_ScalarT], point: _Point[_ScalarT], /
) -> _ScalarT:
"""
Returns squared Euclidean distance between box and a point.
Time complexity:
``O(1)``
Memory complexity:
``O(1)``
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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_context.box_point_squared_metric(
box, point, self._coordinate_factory
)
[docs]
def box_segment_squared_distance(
self, box: _Box[_ScalarT], segment: _Segment[_ScalarT], /
) -> _ScalarT:
"""
Returns squared Euclidean distance between box and a segment.
Time complexity:
``O(1)``
Memory complexity:
``O(1)``
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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_context.box_segment_squared_metric(
box,
segment,
self.dot_product,
self._segments_intersect,
self._coordinate_factory,
self._point_cls,
)
[docs]
def contour_box(self, contour: _Contour[_ScalarT], /) -> _Box[_ScalarT]:
"""
Constructs box from contour.
Time complexity:
``O(vertices_count)``
Memory complexity:
``O(1)``
where ``vertices_count = len(contour.vertices)``.
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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: _Contour[_ScalarT], /
) -> _Point[_ScalarT]:
"""
Constructs centroid of a contour.
Time complexity:
``O(len(contour.vertices))``
Memory complexity:
``O(1)``
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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_context.contour_centroid(
contour, self._coordinate_factory, self._point_cls, self._sqrt
)
[docs]
def contour_length(self, contour: _Contour[_ScalarT], /) -> _ScalarT:
"""
Returns Euclidean length of a contour.
Time complexity:
``O(len(contour.vertices))``
Memory complexity:
``O(1)``
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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))
),
self._zero,
)
[docs]
def contour_segments(
self, contour: _Contour[_ScalarT], /
) -> _Sequence[_Segment[_ScalarT]]:
"""
Constructs segments of a contour.
Time complexity:
``O(len(contour.vertices))``
Memory complexity:
``O(1)``
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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, 0), Point(2, 0)),
... Segment(Point(2, 0), Point(2, 2)),
... Segment(Point(2, 2), Point(0, 2)),
... Segment(Point(0, 2), Point(0, 0)),
... ]
... )
True
"""
segment_cls, vertices = self._segment_cls, contour.vertices
return [
segment_cls(vertices[index], vertices[index + 1])
for index in range(len(vertices) - 1)
] + [segment_cls(vertices[-1], vertices[0])]
[docs]
def contours_box(
self, contours: _Sequence[_Contour[_ScalarT]], /
) -> _Box[_ScalarT]:
"""
Constructs box from contours.
Time complexity:
``O(vertices_count)``
Memory complexity:
``O(1)``
where ``vertices_count = sum(len(contour.vertices)\
for contour in contours)``.
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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: _Contour[_ScalarT], /) -> bool:
"""
Checks if region (given its contour) is convex.
Time complexity:
``O(len(contour.vertices))``
Memory complexity:
``O(1)``
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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 locate_point_in_point_point_point_circle(
self,
point: _Point[_ScalarT],
first: _Point[_ScalarT],
second: _Point[_ScalarT],
third: _Point[_ScalarT],
/,
) -> _Location:
"""
Returns location of point in point-point-point circle.
Time complexity:
``O(1)``
Memory complexity:
``O(1)``
>>> from ground.enums import Location
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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_context.point_point_point_locator(
point, first, second, third, self._zero
)
[docs]
def merged_box(
self, first_box: _Box[_ScalarT], second_box: _Box[_ScalarT], /
) -> _Box[_ScalarT]:
"""
Merges two boxes.
Time complexity:
``O(1)``
Memory complexity:
``O(1)``
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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: _Multipoint[_ScalarT], /
) -> _Point[_ScalarT]:
"""
Constructs centroid of a multipoint.
Time complexity:
``O(len(multipoint.points))``
Memory complexity:
``O(1)``
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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_context.multipoint_centroid(
multipoint, self._coordinate_factory, self._point_cls
)
[docs]
def multipolygon_centroid(
self, multipolygon: _Multipolygon[_ScalarT], /
) -> _Point[_ScalarT]:
"""
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)``.
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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_context.multipolygon_centroid(
multipolygon, self._coordinate_factory, self._point_cls
)
[docs]
def multisegment_centroid(
self, multisegment: _Multisegment[_ScalarT], /
) -> _Point[_ScalarT]:
"""
Constructs centroid of a multisegment.
Time complexity:
``O(len(multisegment.segments))``
Memory complexity:
``O(1)``
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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_context.multisegment_centroid(
multisegment, self._coordinate_factory, self._point_cls, self._sqrt
)
[docs]
def multisegment_length(
self, multisegment: _Multisegment[_ScalarT], /
) -> _ScalarT:
"""
Returns Euclidean length of a multisegment.
Time complexity:
``O(len(multisegment.segments))``
Memory complexity:
``O(1)``
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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
),
self._origin.x,
)
[docs]
def points_convex_hull(
self, points: _Sequence[_Point[_ScalarT]], /
) -> _Sequence[_Point[_ScalarT]]:
"""
Constructs convex hull of points.
Time complexity:
``O(points_count * log(points_count))``
Memory complexity:
``O(points_count)``
where ``points_count = len(points)``.
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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[_Point[_ScalarT]], /
) -> _Box[_ScalarT]:
"""
Constructs box from points.
Time complexity:
``O(len(points))``
Memory complexity:
``O(1)``
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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: _Polygon[_ScalarT], /) -> _Box[_ScalarT]:
"""
Constructs box from polygon.
Time complexity:
``O(vertices_count)``
Memory complexity:
``O(1)``
where ``vertices_count = len(polygon.border.vertices)``.
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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: _Polygon[_ScalarT], /
) -> _Point[_ScalarT]:
"""
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)``.
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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_context.polygon_centroid(
polygon, self._coordinate_factory, self._point_cls
)
[docs]
def polygons_box(
self, polygons: _Sequence[_Polygon[_ScalarT]], /
) -> _Box[_ScalarT]:
"""
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)``.
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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: _Contour[_ScalarT], /
) -> _Point[_ScalarT]:
"""
Constructs centroid of a region given its contour.
Time complexity:
``O(len(contour.vertices))``
Memory complexity:
``O(1)``
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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_context.region_centroid(
contour, self._coordinate_factory, self._point_cls
)
[docs]
def region_signed_area(self, contour: _Contour[_ScalarT], /) -> _ScalarT:
"""
Returns signed area of the region given its contour.
Time complexity:
``O(len(contour.vertices))``
Memory complexity:
``O(1)``
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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_context.region_signed_area(
contour, self._coordinate_factory
)
[docs]
def replace(
self,
/,
*,
box_cls: type[_Box[_ScalarT]] | None = None,
contour_cls: type[_Contour[_ScalarT]] | None = None,
coordinate_factory: _ScalarFactory[_ScalarT] | None = None,
empty_cls: type[_Empty[_ScalarT]] | None = None,
mix_cls: type[_Mix[_ScalarT]] | None = None,
multipoint_cls: type[_Multipoint[_ScalarT]] | None = None,
multipolygon_cls: type[_Multipolygon[_ScalarT]] | None = None,
multisegment_cls: type[_Multisegment[_ScalarT]] | None = None,
point_cls: type[_Point[_ScalarT]] | None = None,
polygon_cls: type[_Polygon[_ScalarT]] | None = None,
segment_cls: type[_Segment[_ScalarT]] | None = None,
sqrt: _SquareRooter[_ScalarT] | None = None,
) -> Context[_ScalarT]:
"""
Constructs context from the original one replacing given parameters.
Time complexity:
``O(1)``
Memory complexity:
``O(1)``
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> from fractions import Fraction
>>> from ground.context import Context
>>> fraction_context = context.replace(coordinate_factory=Fraction)
>>> isinstance(fraction_context, Context)
True
>>> fraction_context.coordinate_factory is Fraction
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
),
coordinate_factory=(
self._coordinate_factory
if coordinate_factory is None
else coordinate_factory
),
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
),
sqrt=self._sqrt if sqrt is None else sqrt,
)
[docs]
def rotate_contour(
self,
contour: _Contour[_ScalarT],
cosine: _ScalarT,
sine: _ScalarT,
center: _Point[_ScalarT],
/,
) -> _Contour[_ScalarT]:
"""
Returns contour rotated by given angle around given center.
Time complexity:
``O(len(contour.vertices))``
Memory complexity:
``O(len(contour.vertices))``
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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_context.rotate_translate_contour(
contour,
cosine,
sine,
*self._rotation_context.point_to_step(center, cosine, sine),
self._contour_cls,
self._point_cls,
)
[docs]
def rotate_contour_around_origin(
self, contour: _Contour[_ScalarT], cosine: _ScalarT, sine: _ScalarT, /
) -> _Contour[_ScalarT]:
"""
Returns contour rotated by given angle around origin.
Time complexity:
``O(len(contour.vertices))``
Memory complexity:
``O(len(contour.vertices))``
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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_context.rotate_contour_around_origin(
contour, cosine, sine, self._contour_cls, self._point_cls
)
[docs]
def rotate_multipoint(
self,
multipoint: _Multipoint[_ScalarT],
cosine: _ScalarT,
sine: _ScalarT,
center: _Point[_ScalarT],
/,
) -> _Multipoint[_ScalarT]:
"""
Returns multipoint rotated by given angle around given center.
Time complexity:
``O(len(multipoint.points))``
Memory complexity:
``O(len(multipoint.points))``
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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_context.rotate_translate_multipoint(
multipoint,
cosine,
sine,
*self._rotation_context.point_to_step(center, cosine, sine),
self._multipoint_cls,
self._point_cls,
)
[docs]
def rotate_multipoint_around_origin(
self,
multipoint: _Multipoint[_ScalarT],
cosine: _ScalarT,
sine: _ScalarT,
/,
) -> _Multipoint[_ScalarT]:
"""
Returns multipoint rotated by given angle around origin.
Time complexity:
``O(len(multipoint.points))``
Memory complexity:
``O(len(multipoint.points))``
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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_context.rotate_multipoint_around_origin(
multipoint, cosine, sine, self._multipoint_cls, self._point_cls
)
[docs]
def rotate_multipolygon(
self,
multipolygon: _Multipolygon[_ScalarT],
cosine: _ScalarT,
sine: _ScalarT,
center: _Point[_ScalarT],
/,
) -> _Multipolygon[_ScalarT]:
"""
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)``.
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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_context.rotate_translate_multipolygon(
multipolygon,
cosine,
sine,
*self._rotation_context.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: _Multipolygon[_ScalarT],
cosine: _ScalarT,
sine: _ScalarT,
/,
) -> _Multipolygon[_ScalarT]:
"""
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)``.
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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_context.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: _Multisegment[_ScalarT],
cosine: _ScalarT,
sine: _ScalarT,
center: _Point[_ScalarT],
/,
) -> _Multisegment[_ScalarT]:
"""
Returns multisegment rotated by given angle around given center.
Time complexity:
``O(1)``
Memory complexity:
``O(1)``
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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_context.rotate_translate_multisegment(
multisegment,
cosine,
sine,
*self._rotation_context.point_to_step(center, cosine, sine),
self._multisegment_cls,
self._point_cls,
self._segment_cls,
)
[docs]
def rotate_multisegment_around_origin(
self,
multisegment: _Multisegment[_ScalarT],
cosine: _ScalarT,
sine: _ScalarT,
/,
) -> _Multisegment[_ScalarT]:
"""
Returns multisegment rotated by given angle around origin.
Time complexity:
``O(len(multisegment.segments))``
Memory complexity:
``O(len(multisegment.segments))``
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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_context.rotate_multisegment_around_origin(
multisegment,
cosine,
sine,
self._multisegment_cls,
self._point_cls,
self._segment_cls,
)
[docs]
def rotate_point(
self,
point: _Point[_ScalarT],
cosine: _ScalarT,
sine: _ScalarT,
center: _Point[_ScalarT],
/,
) -> _Point[_ScalarT]:
"""
Returns point rotated by given angle around given center.
Time complexity:
``O(1)``
Memory complexity:
``O(1)``
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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_context.rotate_translate_point(
point,
cosine,
sine,
*self._rotation_context.point_to_step(center, cosine, sine),
self._point_cls,
)
[docs]
def rotate_point_around_origin(
self, point: _Point[_ScalarT], cosine: _ScalarT, sine: _ScalarT, /
) -> _Point[_ScalarT]:
"""
Returns point rotated by given angle around origin.
Time complexity:
``O(1)``
Memory complexity:
``O(1)``
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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_context.rotate_point_around_origin(
point, cosine, sine, self._point_cls
)
[docs]
def rotate_polygon(
self,
polygon: _Polygon[_ScalarT],
cosine: _ScalarT,
sine: _ScalarT,
center: _Point[_ScalarT],
/,
) -> _Polygon[_ScalarT]:
"""
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)``.
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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_context.rotate_translate_polygon(
polygon,
cosine,
sine,
*self._rotation_context.point_to_step(center, cosine, sine),
self._contour_cls,
self._point_cls,
self._polygon_cls,
)
[docs]
def rotate_polygon_around_origin(
self, polygon: _Polygon[_ScalarT], cosine: _ScalarT, sine: _ScalarT, /
) -> _Polygon[_ScalarT]:
"""
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)``.
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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_context.rotate_polygon_around_origin(
polygon,
cosine,
sine,
self._contour_cls,
self._point_cls,
self._polygon_cls,
)
[docs]
def rotate_segment(
self,
segment: _Segment[_ScalarT],
cosine: _ScalarT,
sine: _ScalarT,
center: _Point[_ScalarT],
/,
) -> _Segment[_ScalarT]:
"""
Returns segment rotated by given angle around given center.
Time complexity:
``O(1)``
Memory complexity:
``O(1)``
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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_context.rotate_translate_segment(
segment,
cosine,
sine,
*self._rotation_context.point_to_step(center, cosine, sine),
self._point_cls,
self._segment_cls,
)
[docs]
def rotate_segment_around_origin(
self, segment: _Segment[_ScalarT], cosine: _ScalarT, sine: _ScalarT, /
) -> _Segment[_ScalarT]:
"""
Returns segment rotated by given angle around origin.
Time complexity:
``O(1)``
Memory complexity:
``O(1)``
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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_context.rotate_segment_around_origin(
segment, cosine, sine, self._point_cls, self._segment_cls
)
[docs]
def scale_contour(
self,
contour: _Contour[_ScalarT],
factor_x: _ScalarT,
factor_y: _ScalarT,
/,
) -> _Contour[_ScalarT] | _Multipoint[_ScalarT] | _Segment[_ScalarT]:
"""
Returns contour scaled by given factor.
Time complexity:
``O(len(contour.vertices))``
Memory complexity:
``O(len(contour.vertices))``
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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_context.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: _Multipoint[_ScalarT],
factor_x: _ScalarT,
factor_y: _ScalarT,
/,
) -> _Multipoint[_ScalarT]:
"""
Returns multipoint scaled by given factor.
Time complexity:
``O(len(multipoint.points))``
Memory complexity:
``O(len(multipoint.points))``
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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_context.scale_multipoint(
multipoint,
factor_x,
factor_y,
self._multipoint_cls,
self._point_cls,
)
[docs]
def scale_multipolygon(
self,
multipolygon: _Multipolygon[_ScalarT],
factor_x: _ScalarT,
factor_y: _ScalarT,
/,
) -> (
_Multipoint[_ScalarT]
| _Multipolygon[_ScalarT]
| _Multisegment[_ScalarT]
):
"""
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)``.
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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_context.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: _Multisegment[_ScalarT],
factor_x: _ScalarT,
factor_y: _ScalarT,
/,
) -> (
_Empty[_ScalarT]
| _Linear[_ScalarT]
| _Mix[_ScalarT]
| _Multipoint[_ScalarT]
| _Shaped[_ScalarT]
):
"""
Returns multisegment scaled by given factor.
Time complexity:
``O(len(multisegment.segments))``
Memory complexity:
``O(len(multisegment.segments))``
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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_context.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: _Point[_ScalarT],
factor_x: _ScalarT,
factor_y: _ScalarT,
/,
) -> _Point[_ScalarT]:
"""
Returns point scaled by given factor.
Time complexity:
``O(1)``
Memory complexity:
``O(1)``
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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_context.scale_point(
point, factor_x, factor_y, self._point_cls
)
[docs]
def scale_polygon(
self,
polygon: _Polygon[_ScalarT],
factor_x: _ScalarT,
factor_y: _ScalarT,
/,
) -> _Multipoint[_ScalarT] | _Polygon[_ScalarT] | _Segment[_ScalarT]:
"""
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)``.
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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_context.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: _Segment[_ScalarT],
factor_x: _ScalarT,
factor_y: _ScalarT,
/,
) -> _Multipoint[_ScalarT] | _Segment[_ScalarT]:
"""
Returns segment scaled by given factor.
Time complexity:
``O(1)``
Memory complexity:
``O(1)``
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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_context.scale_segment(
segment,
factor_x,
factor_y,
self._multipoint_cls,
self._point_cls,
self._segment_cls,
)
[docs]
def segment_box(self, segment: _Segment[_ScalarT], /) -> _Box[_ScalarT]:
"""
Constructs box from segment.
Time complexity:
``O(1)``
Memory complexity:
``O(1)``
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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: _Segment[_ScalarT], /
) -> _Point[_ScalarT]:
"""
Constructs centroid of a segment.
Time complexity:
``O(1)``
Memory complexity:
``O(1)``
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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_context.segment_centroid(
segment, self._coordinate_factory, self._point_cls
)
[docs]
def segment_contains_point(
self, segment: _Segment[_ScalarT], point: _Point[_ScalarT], /
) -> bool:
"""
Checks if a segment contains given point.
Time complexity:
``O(1)``
Memory complexity:
``O(1)``
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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_context.containment_checker(
segment.start, segment.end, point, self.angle_orientation
)
[docs]
def segment_length(self, segment: _Segment[_ScalarT], /) -> _ScalarT:
"""
Returns Euclidean length of a segment.
Time complexity:
``O(1)``
Memory complexity:
``O(1)``
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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: _Segment[_ScalarT], point: _Point[_ScalarT], /
) -> _ScalarT:
"""
Returns squared Euclidean distance between segment and a point.
Time complexity:
``O(1)``
Memory complexity:
``O(1)``
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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_context.segment_point_squared_metric(
segment.start,
segment.end,
point,
self.dot_product,
self._coordinate_factory,
)
[docs]
def segments_box(
self, segments: _Sequence[_Segment[_ScalarT]], /
) -> _Box[_ScalarT]:
"""
Constructs box from segments.
Time complexity:
``O(len(segments))``
Memory complexity:
``O(1)``
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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: _Segment[_ScalarT], second: _Segment[_ScalarT], /
) -> _Point[_ScalarT]:
"""
Returns intersection point of two segments.
Time complexity:
``O(1)``
Memory complexity:
``O(1)``
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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_context.intersector(
first.start,
first.end,
second.start,
second.end,
self._point_cls,
self._segment_contains_point,
)
[docs]
def segments_relation(
self, test: _Segment[_ScalarT], goal: _Segment[_ScalarT], /
) -> _Relation:
"""
Returns relation between two segments.
Time complexity:
``O(1)``
Memory complexity:
``O(1)``
>>> from ground.enums import Relation
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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_context.relater(
test.start, test.end, goal.start, goal.end, self.angle_orientation
)
[docs]
def segments_squared_distance(
self, first: _Segment[_ScalarT], second: _Segment[_ScalarT], /
) -> _ScalarT:
"""
Returns squared Euclidean distance between two segments.
Time complexity:
``O(1)``
Memory complexity:
``O(1)``
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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_context.segment_segment_squared_metric(
first.start,
first.end,
second.start,
second.end,
self.dot_product,
self._segments_intersect,
self._coordinate_factory,
)
[docs]
def translate_contour(
self,
contour: _Contour[_ScalarT],
step_x: _ScalarT,
step_y: _ScalarT,
/,
) -> _Contour[_ScalarT]:
"""
Returns contour translated by given step.
Time complexity:
``O(len(contour.vertices))``
Memory complexity:
``O(len(contour.vertices))``
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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_context.translate_contour(
contour, step_x, step_y, self._contour_cls, self._point_cls
)
[docs]
def translate_multipoint(
self,
multipoint: _Multipoint[_ScalarT],
step_x: _ScalarT,
step_y: _ScalarT,
/,
) -> _Multipoint[_ScalarT]:
"""
Returns multipoint translated by given step.
Time complexity:
``O(len(multipoint.points))``
Memory complexity:
``O(len(multipoint.points))``
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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_context.translate_multipoint(
multipoint, step_x, step_y, self._multipoint_cls, self._point_cls
)
[docs]
def translate_multipolygon(
self,
multipolygon: _Multipolygon[_ScalarT],
step_x: _ScalarT,
step_y: _ScalarT,
/,
) -> _Multipolygon[_ScalarT]:
"""
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)``.
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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_context.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: _Multisegment[_ScalarT],
step_x: _ScalarT,
step_y: _ScalarT,
/,
) -> _Multisegment[_ScalarT]:
"""
Returns multisegment translated by given step.
Time complexity:
``O(len(multisegment.segments))``
Memory complexity:
``O(len(multisegment.segments))``
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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_context.translate_multisegment(
multisegment,
step_x,
step_y,
self._multisegment_cls,
self._point_cls,
self._segment_cls,
)
[docs]
def translate_point(
self, point: _Point[_ScalarT], step_x: _ScalarT, step_y: _ScalarT, /
) -> _Point[_ScalarT]:
"""
Returns point translated by given step.
Time complexity:
``O(1)``
Memory complexity:
``O(1)``
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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_context.translate_point(
point, step_x, step_y, self._point_cls
)
[docs]
def translate_polygon(
self,
polygon: _Polygon[_ScalarT],
step_x: _ScalarT,
step_y: _ScalarT,
/,
) -> _Polygon[_ScalarT]:
"""
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)``.
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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_context.translate_polygon(
polygon,
step_x,
step_y,
self._contour_cls,
self._point_cls,
self._polygon_cls,
)
[docs]
def translate_segment(
self,
segment: _Segment[_ScalarT],
step_x: _ScalarT,
step_y: _ScalarT,
/,
) -> _Segment[_ScalarT]:
"""
Returns segment translated by given step.
Time complexity:
``O(1)``
Memory complexity:
``O(1)``
>>> import math
>>> from fractions import Fraction
>>> from ground.context import Context
>>> context = Context(coordinate_factory=Fraction, sqrt=math.sqrt)
>>> 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_context.translate_segment(
segment, step_x, step_y, self._point_cls, self._segment_cls
)
_angular_context: _angular.Context[_ScalarT]
_box_cls: type[_Box[_ScalarT]]
_centroidal_context: _centroidal.Context[_ScalarT]
_circular_context: _circular.Context[_ScalarT]
_contour_cls: type[_Contour[_ScalarT]]
_coordinate_factory: _ScalarFactory[_ScalarT]
_empty: _Empty[_ScalarT]
_empty_cls: type[_Empty[_ScalarT]]
_measured_context: _measured.Context[_ScalarT]
_metric_context: _metric.Context[_ScalarT]
_mix_cls: type[_Mix[_ScalarT]]
_multipoint_cls: type[_Multipoint[_ScalarT]]
_multipolygon_cls: type[_Multipolygon[_ScalarT]]
_multisegment_cls: type[_Multisegment[_ScalarT]]
_origin: _Point[_ScalarT]
_point_cls: type[_Point[_ScalarT]]
_polygon_cls: type[_Polygon[_ScalarT]]
_rotation_context: _rotation.Context[_ScalarT]
_scaling_context: _scaling.Context[_ScalarT]
_segment_cls: type[_Segment[_ScalarT]]
_segment_context: _segment.Context[_ScalarT]
_sqrt: _SquareRooter[_ScalarT]
_translation_context: _translation.Context[_ScalarT]
_vector_context: _vector.Context[_ScalarT]
_zero: _ScalarT
def _segment_contains_point(
self,
start: _Point[_ScalarT],
end: _Point[_ScalarT],
point: _Point[_ScalarT],
/,
) -> bool:
return self._segment_context.containment_checker(
start, end, point, self.angle_orientation
)
def _segments_intersect(
self,
first_start: _Point[_ScalarT],
first_end: _Point[_ScalarT],
second_start: _Point[_ScalarT],
second_end: _Point[_ScalarT],
/,
) -> bool:
return self._segment_context.collision_detector(
first_start,
first_end,
second_start,
second_end,
self.angle_orientation,
)
__slots__ = (
'_angular_context',
'_box_cls',
'_centroidal_context',
'_circular_context',
'_contour_cls',
'_coordinate_factory',
'_empty',
'_empty_cls',
'_measured_context',
'_metric_context',
'_mix_cls',
'_multipoint_cls',
'_multipolygon_cls',
'_multisegment_cls',
'_origin',
'_point_cls',
'_polygon_cls',
'_rotation_context',
'_scaling_context',
'_segment_cls',
'_segment_context',
'_sqrt',
'_translation_context',
'_vector_context',
'_zero',
)
def __new__(
cls,
/,
*,
box_cls: type[_Box[_ScalarT]] = _geometries.Box,
contour_cls: type[_Contour[_ScalarT]] = _geometries.Contour,
coordinate_factory: _Callable[[int], _ScalarT],
empty_cls: type[_Empty[_ScalarT]] = _geometries.Empty,
mix_cls: type[_Mix[_ScalarT]] = _geometries.Mix,
multipoint_cls: type[_Multipoint[_ScalarT]] = _geometries.Multipoint,
multipolygon_cls: type[
_Multipolygon[_ScalarT]
] = _geometries.Multipolygon,
multisegment_cls: type[
_Multisegment[_ScalarT]
] = _geometries.Multisegment,
point_cls: type[_Point[_ScalarT]] = _geometries.Point,
polygon_cls: type[_Polygon[_ScalarT]] = _geometries.Polygon,
segment_cls: type[_Segment[_ScalarT]] = _geometries.Segment,
sqrt: _SquareRooter[_ScalarT],
) -> _Self:
zero = coordinate_factory(0)
self = super().__new__(cls)
(
self._box_cls,
self._contour_cls,
self._coordinate_factory,
self._empty,
self._empty_cls,
self._mix_cls,
self._multipoint_cls,
self._multipolygon_cls,
self._multisegment_cls,
self._origin,
self._point_cls,
self._polygon_cls,
self._segment_cls,
self._sqrt,
self._zero,
) = (
box_cls,
contour_cls,
coordinate_factory,
empty_cls(),
empty_cls,
mix_cls,
multipoint_cls,
multipolygon_cls,
multisegment_cls,
point_cls(zero, zero),
point_cls,
polygon_cls,
segment_cls,
sqrt,
zero,
)
(
self._angular_context,
self._centroidal_context,
self._circular_context,
self._measured_context,
self._metric_context,
self._rotation_context,
self._scaling_context,
self._segment_context,
self._translation_context,
self._vector_context,
) = (
_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,
)
return self
def __eq__(self, other: _Any, /) -> _Any:
return (
(
self._box_cls is other._box_cls
and self._contour_cls is other._contour_cls
and self._coordinate_factory is other._coordinate_factory
and self._empty_cls is other._empty_cls
and self._mix_cls is other._mix_cls
and self._multipoint_cls is other._multipoint_cls
and self._multipolygon_cls is other._multipolygon_cls
and self._multisegment_cls is other._multisegment_cls
and self._point_cls is other._point_cls
and self._polygon_cls is other._polygon_cls
and self._segment_cls is other._segment_cls
and self._sqrt is other._sqrt
)
if isinstance(other, Context)
else NotImplemented
)
__repr__ = _generate_repr(
__new__, argument_serializer=_serializers.complex_, skip_defaults=True
)