Add existing to tracked
This commit is contained in:
@@ -0,0 +1,250 @@
|
||||
"""
|
||||
cairocffi.matrix
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
Transformation matrices.
|
||||
|
||||
:copyright: Copyright 2013-2019 by Simon Sapin
|
||||
:license: BSD, see LICENSE for details.
|
||||
|
||||
"""
|
||||
|
||||
from . import _check_status, cairo, ffi
|
||||
|
||||
|
||||
class Matrix(object):
|
||||
"""A 2D transformation matrix.
|
||||
|
||||
Matrices are used throughout cairo to convert between
|
||||
different coordinate spaces.
|
||||
A :class:`Matrix` holds an affine transformation,
|
||||
such as a scale, rotation, shear, or a combination of these.
|
||||
The transformation of a point (x,y) is given by::
|
||||
|
||||
x_new = xx * x + xy * y + x0
|
||||
y_new = yx * x + yy * y + y0
|
||||
|
||||
The current transformation matrix of a :class:`Context`,
|
||||
represented as a :class:`Matrix`,
|
||||
defines the transformation from user-space coordinates
|
||||
to device-space coordinates.
|
||||
See :meth:`Context.get_matrix` and :meth:`Context.set_matrix`.
|
||||
|
||||
The default values produce an identity matrix.
|
||||
|
||||
Matrices can be compared with ``m1 == m2`` and ``m2 != m2``
|
||||
as well as multiplied with ``m3 = m1 * m2``.
|
||||
|
||||
"""
|
||||
def __init__(self, xx=1, yx=0, xy=0, yy=1, x0=0, y0=0):
|
||||
self._pointer = ffi.new('cairo_matrix_t *')
|
||||
cairo.cairo_matrix_init(self._pointer, xx, yx, xy, yy, x0, y0)
|
||||
|
||||
@classmethod
|
||||
def init_rotate(cls, radians):
|
||||
"""Return a new :class:`Matrix` for a transformation
|
||||
that rotates by ``radians``.
|
||||
|
||||
:type radians: float
|
||||
:param radians:
|
||||
Angle of rotation, in radians.
|
||||
The direction of rotation is defined such that
|
||||
positive angles rotate in the direction
|
||||
from the positive X axis toward the positive Y axis.
|
||||
With the default axis orientation of cairo,
|
||||
positive angles rotate in a clockwise direction.
|
||||
|
||||
"""
|
||||
result = cls()
|
||||
cairo.cairo_matrix_init_rotate(result._pointer, radians)
|
||||
return result
|
||||
|
||||
def as_tuple(self):
|
||||
"""Return all of the matrix’s components.
|
||||
|
||||
:returns: A ``(xx, yx, xy, yy, x0, y0)`` tuple of floats.
|
||||
|
||||
"""
|
||||
ptr = self._pointer
|
||||
return (ptr.xx, ptr.yx, ptr.xy, ptr.yy, ptr.x0, ptr.y0)
|
||||
|
||||
def copy(self):
|
||||
"""Return a new copy of this matrix."""
|
||||
return type(self)(*self.as_tuple())
|
||||
|
||||
def __getitem__(self, index):
|
||||
return getattr(
|
||||
self._pointer, ('xx', 'yx', 'xy', 'yy', 'x0', 'y0')[index])
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self.as_tuple())
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.as_tuple() == other.as_tuple()
|
||||
|
||||
def __ne__(self, other):
|
||||
return self.as_tuple() != other.as_tuple()
|
||||
|
||||
def __repr__(self):
|
||||
class_ = type(self)
|
||||
return '%s(%g, %g, %g, %g, %g, %g)' % (
|
||||
(class_.__name__, *self.as_tuple()))
|
||||
|
||||
def multiply(self, other):
|
||||
"""Multiply with another matrix
|
||||
and return the result as a new :class:`Matrix` object.
|
||||
Same as ``self * other``.
|
||||
|
||||
"""
|
||||
res = Matrix()
|
||||
cairo.cairo_matrix_multiply(
|
||||
res._pointer, self._pointer, other._pointer)
|
||||
return res
|
||||
|
||||
__mul__ = multiply
|
||||
|
||||
def translate(self, tx, ty):
|
||||
"""Applies a translation by ``tx``, ``ty``
|
||||
to the transformation in this matrix.
|
||||
|
||||
The effect of the new transformation is to
|
||||
first translate the coordinates by ``tx`` and ``ty``,
|
||||
then apply the original transformation to the coordinates.
|
||||
|
||||
.. note::
|
||||
This changes the matrix in-place.
|
||||
|
||||
:param tx: Amount to translate in the X direction.
|
||||
:param ty: Amount to translate in the Y direction.
|
||||
:type tx: float
|
||||
:type ty: float
|
||||
|
||||
"""
|
||||
cairo.cairo_matrix_translate(self._pointer, tx, ty)
|
||||
|
||||
def scale(self, sx, sy=None):
|
||||
"""Applies scaling by ``sx``, ``sy``
|
||||
to the transformation in this matrix.
|
||||
|
||||
The effect of the new transformation is to
|
||||
first scale the coordinates by ``sx`` and ``sy``,
|
||||
then apply the original transformation to the coordinates.
|
||||
|
||||
If ``sy`` is omitted, it is the same as ``sx``
|
||||
so that scaling preserves aspect ratios.
|
||||
|
||||
.. note::
|
||||
This changes the matrix in-place.
|
||||
|
||||
:param sx: Scale factor in the X direction.
|
||||
:param sy: Scale factor in the Y direction.
|
||||
:type sx: float
|
||||
:type sy: float
|
||||
|
||||
"""
|
||||
if sy is None:
|
||||
sy = sx
|
||||
cairo.cairo_matrix_scale(self._pointer, sx, sy)
|
||||
|
||||
def rotate(self, radians):
|
||||
"""Applies a rotation by ``radians``
|
||||
to the transformation in this matrix.
|
||||
|
||||
The effect of the new transformation is to
|
||||
first rotate the coordinates by ``radians``,
|
||||
then apply the original transformation to the coordinates.
|
||||
|
||||
.. note::
|
||||
This changes the matrix in-place.
|
||||
|
||||
:type radians: float
|
||||
:param radians:
|
||||
Angle of rotation, in radians.
|
||||
The direction of rotation is defined such that positive angles
|
||||
rotate in the direction from the positive X axis
|
||||
toward the positive Y axis.
|
||||
With the default axis orientation of cairo,
|
||||
positive angles rotate in a clockwise direction.
|
||||
|
||||
"""
|
||||
cairo.cairo_matrix_rotate(self._pointer, radians)
|
||||
|
||||
def invert(self):
|
||||
"""Changes matrix to be the inverse of its original value.
|
||||
Not all transformation matrices have inverses;
|
||||
if the matrix collapses points together (it is degenerate),
|
||||
then it has no inverse and this function will fail.
|
||||
|
||||
.. note::
|
||||
This changes the matrix in-place.
|
||||
|
||||
:raises: :exc:`CairoError` on degenerate matrices.
|
||||
|
||||
"""
|
||||
_check_status(cairo.cairo_matrix_invert(self._pointer))
|
||||
|
||||
def inverted(self):
|
||||
"""Return the inverse of this matrix. See :meth:`invert`.
|
||||
|
||||
:raises: :exc:`CairoError` on degenerate matrices.
|
||||
:returns: A new :class:`Matrix` object.
|
||||
|
||||
"""
|
||||
matrix = self.copy()
|
||||
matrix.invert()
|
||||
return matrix
|
||||
|
||||
def transform_point(self, x, y):
|
||||
"""Transforms the point ``(x, y)`` by this matrix.
|
||||
|
||||
:param x: X position.
|
||||
:param y: Y position.
|
||||
:type x: float
|
||||
:type y: float
|
||||
:returns: A ``(new_x, new_y)`` tuple of floats.
|
||||
|
||||
"""
|
||||
xy = ffi.new('double[2]', [x, y])
|
||||
cairo.cairo_matrix_transform_point(self._pointer, xy + 0, xy + 1)
|
||||
return tuple(xy)
|
||||
|
||||
def transform_distance(self, dx, dy):
|
||||
"""Transforms the distance vector ``(dx, dy)`` by this matrix.
|
||||
This is similar to :meth:`transform_point`
|
||||
except that the translation components of the transformation
|
||||
are ignored.
|
||||
The calculation of the returned vector is as follows::
|
||||
|
||||
dx2 = dx1 * xx + dy1 * xy
|
||||
dy2 = dx1 * yx + dy1 * yy
|
||||
|
||||
Affine transformations are position invariant,
|
||||
so the same vector always transforms to the same vector.
|
||||
If ``(x1, y1)`` transforms to ``(x2, y2)``
|
||||
then ``(x1 + dx1, y1 + dy1)`` will transform
|
||||
to ``(x1 + dx2, y1 + dy2)`` for all values of ``x1`` and ``x2``.
|
||||
|
||||
:param dx: X component of a distance vector.
|
||||
:param dy: Y component of a distance vector.
|
||||
:type dx: float
|
||||
:type dy: float
|
||||
:returns: A ``(new_dx, new_dy)`` tuple of floats.
|
||||
|
||||
"""
|
||||
xy = ffi.new('double[2]', [dx, dy])
|
||||
cairo.cairo_matrix_transform_distance(self._pointer, xy + 0, xy + 1)
|
||||
return tuple(xy)
|
||||
|
||||
def _component_property(name): # noqa: N805
|
||||
return property(
|
||||
lambda self: getattr(self._pointer, name),
|
||||
lambda self, value: setattr(self._pointer, name, value),
|
||||
doc='Read-write attribute access to a single float component.')
|
||||
|
||||
xx = _component_property('xx')
|
||||
yx = _component_property('yx')
|
||||
xy = _component_property('xy')
|
||||
yy = _component_property('yy')
|
||||
x0 = _component_property('x0')
|
||||
y0 = _component_property('y0')
|
||||
del _component_property
|
||||
Reference in New Issue
Block a user