sketchingpy.transform
Data structures providing transformation matrix functionality if native logic is not available.
Data structures providing Python-based transformation matrix functionality if native logic is not available in the underlying renderer.
License:
BSD
1"""Data structures providing transformation matrix functionality if native logic is not available. 2 3Data structures providing Python-based transformation matrix functionality if native logic is not 4available in the underlying renderer. 5 6License: 7 BSD 8""" 9 10import math 11import typing 12 13has_numpy = False 14try: 15 import numpy 16 has_numpy = True 17except: 18 pass 19 20 21class TransformedPoint: 22 """A point which has gone through zero or more transformations.""" 23 24 def __init__(self, x: float, y: float, scale: float, rotation: float): 25 """Create a new transformed point. 26 27 Args: 28 x: Horizontal coordinate for this point after transformation. 29 y: Vertical coordinate for this point after transformation. 30 scale: The overall scale factor applied to this point. 31 rotation: The overall rotation applied to this point. 32 """ 33 self._x = x 34 self._y = y 35 self._scale = scale 36 self._rotation = rotation 37 38 def get_x(self) -> float: 39 """Get the post-transformation x coordinate. 40 41 Returns: 42 Horizontal coordinate for this point after transformation. 43 """ 44 return self._x 45 46 def get_y(self) -> float: 47 """Get the post-transformation y coordinate. 48 49 Returns: 50 Vertical coordinate for this point after transformation. 51 """ 52 return self._y 53 54 def get_scale(self) -> float: 55 """Get the overall scale reflected in this point. 56 57 Returns: 58 The overall scale factor applied to this point. 59 """ 60 return self._scale 61 62 def get_rotation(self) -> float: 63 """Get the overall rotation reflected in this point. 64 65 Returns: 66 The overall rotation factor applied to this point. 67 """ 68 return self._rotation 69 70 71class Transformer: 72 """Utility to transform points.""" 73 74 def __init__(self, matrix: typing.Optional['numpy.ndarray'] = None, scale: float = 1, 75 rotation: float = 0): 76 """Create a new transformer. 77 78 Args: 79 matrix: Starting transformation matrix. 80 scale: Starting overall scale. 81 rotation: Starting overall rotation. 82 """ 83 84 if not has_numpy: 85 raise RuntimeError('Need numpy in order to use transformer on this renderer.') 86 87 matrix_unset = matrix is None 88 scale_unset = abs(scale - 1) < 0.00001 89 rotation_unset = abs(rotation - 0) < 0.00001 90 91 self._is_default = matrix_unset and scale_unset and rotation_unset 92 self._matrix = numpy.identity(3) if matrix is None else matrix 93 self._scale = scale 94 self._rotation = rotation 95 96 def translate(self, x: float, y: float): 97 """Apply a translation to the current transformation matrix. 98 99 Args: 100 x: By how much to offset the horizontal coordinate. 101 y: By how much to offset the vertical coordinate. 102 """ 103 transformation = numpy.identity(3) 104 transformation[0][2] = x 105 transformation[1][2] = y 106 self._matrix = numpy.dot(self._matrix, transformation) 107 self._is_default = False 108 109 def scale(self, scale: float): 110 """Apply a scale to the current transformation matrix. 111 112 Args: 113 scale: The scale to apply. 114 """ 115 transformation = numpy.identity(3) 116 transformation[0][0] = scale 117 transformation[1][1] = scale 118 self._matrix = numpy.dot(self._matrix, transformation) 119 self._scale *= scale 120 self._is_default = False 121 122 def rotate(self, angle: float): 123 """Apply a rotation to the current transforation matrix counter-clockwise. 124 125 Args: 126 angle: The angle of rotation to apply as radians. 127 """ 128 cos_angle = math.cos(angle) 129 sin_angle = math.sin(angle) 130 131 transformation = numpy.identity(3) 132 transformation[0][0] = cos_angle 133 transformation[1][1] = cos_angle 134 transformation[1][0] = -1 * sin_angle 135 transformation[0][1] = sin_angle 136 137 self._matrix = numpy.dot(self._matrix, transformation) 138 self._rotation += angle 139 self._is_default = False 140 141 def transform(self, x: float, y: float) -> TransformedPoint: 142 """Transform a point. 143 144 Args: 145 x: The horizontal coordinate to be transformed. 146 y: The vertical coordinate to be transformed. 147 148 Returns: 149 Point after transformation. 150 """ 151 if self._is_default: 152 return TransformedPoint(x, y, self._scale, self._rotation) 153 154 input_array = numpy.array([x, y, 1]) 155 output = numpy.dot(self._matrix, input_array) 156 157 x = output[0] 158 y = output[1] 159 160 return TransformedPoint(x, y, self._scale, self._rotation) 161 162 def quick_copy(self) -> 'Transformer': 163 """Create a shallow copy of this transformer. 164 165 Returns: 166 Transformer which has the same transform matrix as this original transformer. 167 """ 168 return Transformer(self._matrix, self._scale, self._rotation)
22class TransformedPoint: 23 """A point which has gone through zero or more transformations.""" 24 25 def __init__(self, x: float, y: float, scale: float, rotation: float): 26 """Create a new transformed point. 27 28 Args: 29 x: Horizontal coordinate for this point after transformation. 30 y: Vertical coordinate for this point after transformation. 31 scale: The overall scale factor applied to this point. 32 rotation: The overall rotation applied to this point. 33 """ 34 self._x = x 35 self._y = y 36 self._scale = scale 37 self._rotation = rotation 38 39 def get_x(self) -> float: 40 """Get the post-transformation x coordinate. 41 42 Returns: 43 Horizontal coordinate for this point after transformation. 44 """ 45 return self._x 46 47 def get_y(self) -> float: 48 """Get the post-transformation y coordinate. 49 50 Returns: 51 Vertical coordinate for this point after transformation. 52 """ 53 return self._y 54 55 def get_scale(self) -> float: 56 """Get the overall scale reflected in this point. 57 58 Returns: 59 The overall scale factor applied to this point. 60 """ 61 return self._scale 62 63 def get_rotation(self) -> float: 64 """Get the overall rotation reflected in this point. 65 66 Returns: 67 The overall rotation factor applied to this point. 68 """ 69 return self._rotation
A point which has gone through zero or more transformations.
25 def __init__(self, x: float, y: float, scale: float, rotation: float): 26 """Create a new transformed point. 27 28 Args: 29 x: Horizontal coordinate for this point after transformation. 30 y: Vertical coordinate for this point after transformation. 31 scale: The overall scale factor applied to this point. 32 rotation: The overall rotation applied to this point. 33 """ 34 self._x = x 35 self._y = y 36 self._scale = scale 37 self._rotation = rotation
Create a new transformed point.
Arguments:
- x: Horizontal coordinate for this point after transformation.
- y: Vertical coordinate for this point after transformation.
- scale: The overall scale factor applied to this point.
- rotation: The overall rotation applied to this point.
39 def get_x(self) -> float: 40 """Get the post-transformation x coordinate. 41 42 Returns: 43 Horizontal coordinate for this point after transformation. 44 """ 45 return self._x
Get the post-transformation x coordinate.
Returns:
Horizontal coordinate for this point after transformation.
47 def get_y(self) -> float: 48 """Get the post-transformation y coordinate. 49 50 Returns: 51 Vertical coordinate for this point after transformation. 52 """ 53 return self._y
Get the post-transformation y coordinate.
Returns:
Vertical coordinate for this point after transformation.
55 def get_scale(self) -> float: 56 """Get the overall scale reflected in this point. 57 58 Returns: 59 The overall scale factor applied to this point. 60 """ 61 return self._scale
Get the overall scale reflected in this point.
Returns:
The overall scale factor applied to this point.
63 def get_rotation(self) -> float: 64 """Get the overall rotation reflected in this point. 65 66 Returns: 67 The overall rotation factor applied to this point. 68 """ 69 return self._rotation
Get the overall rotation reflected in this point.
Returns:
The overall rotation factor applied to this point.
72class Transformer: 73 """Utility to transform points.""" 74 75 def __init__(self, matrix: typing.Optional['numpy.ndarray'] = None, scale: float = 1, 76 rotation: float = 0): 77 """Create a new transformer. 78 79 Args: 80 matrix: Starting transformation matrix. 81 scale: Starting overall scale. 82 rotation: Starting overall rotation. 83 """ 84 85 if not has_numpy: 86 raise RuntimeError('Need numpy in order to use transformer on this renderer.') 87 88 matrix_unset = matrix is None 89 scale_unset = abs(scale - 1) < 0.00001 90 rotation_unset = abs(rotation - 0) < 0.00001 91 92 self._is_default = matrix_unset and scale_unset and rotation_unset 93 self._matrix = numpy.identity(3) if matrix is None else matrix 94 self._scale = scale 95 self._rotation = rotation 96 97 def translate(self, x: float, y: float): 98 """Apply a translation to the current transformation matrix. 99 100 Args: 101 x: By how much to offset the horizontal coordinate. 102 y: By how much to offset the vertical coordinate. 103 """ 104 transformation = numpy.identity(3) 105 transformation[0][2] = x 106 transformation[1][2] = y 107 self._matrix = numpy.dot(self._matrix, transformation) 108 self._is_default = False 109 110 def scale(self, scale: float): 111 """Apply a scale to the current transformation matrix. 112 113 Args: 114 scale: The scale to apply. 115 """ 116 transformation = numpy.identity(3) 117 transformation[0][0] = scale 118 transformation[1][1] = scale 119 self._matrix = numpy.dot(self._matrix, transformation) 120 self._scale *= scale 121 self._is_default = False 122 123 def rotate(self, angle: float): 124 """Apply a rotation to the current transforation matrix counter-clockwise. 125 126 Args: 127 angle: The angle of rotation to apply as radians. 128 """ 129 cos_angle = math.cos(angle) 130 sin_angle = math.sin(angle) 131 132 transformation = numpy.identity(3) 133 transformation[0][0] = cos_angle 134 transformation[1][1] = cos_angle 135 transformation[1][0] = -1 * sin_angle 136 transformation[0][1] = sin_angle 137 138 self._matrix = numpy.dot(self._matrix, transformation) 139 self._rotation += angle 140 self._is_default = False 141 142 def transform(self, x: float, y: float) -> TransformedPoint: 143 """Transform a point. 144 145 Args: 146 x: The horizontal coordinate to be transformed. 147 y: The vertical coordinate to be transformed. 148 149 Returns: 150 Point after transformation. 151 """ 152 if self._is_default: 153 return TransformedPoint(x, y, self._scale, self._rotation) 154 155 input_array = numpy.array([x, y, 1]) 156 output = numpy.dot(self._matrix, input_array) 157 158 x = output[0] 159 y = output[1] 160 161 return TransformedPoint(x, y, self._scale, self._rotation) 162 163 def quick_copy(self) -> 'Transformer': 164 """Create a shallow copy of this transformer. 165 166 Returns: 167 Transformer which has the same transform matrix as this original transformer. 168 """ 169 return Transformer(self._matrix, self._scale, self._rotation)
Utility to transform points.
75 def __init__(self, matrix: typing.Optional['numpy.ndarray'] = None, scale: float = 1, 76 rotation: float = 0): 77 """Create a new transformer. 78 79 Args: 80 matrix: Starting transformation matrix. 81 scale: Starting overall scale. 82 rotation: Starting overall rotation. 83 """ 84 85 if not has_numpy: 86 raise RuntimeError('Need numpy in order to use transformer on this renderer.') 87 88 matrix_unset = matrix is None 89 scale_unset = abs(scale - 1) < 0.00001 90 rotation_unset = abs(rotation - 0) < 0.00001 91 92 self._is_default = matrix_unset and scale_unset and rotation_unset 93 self._matrix = numpy.identity(3) if matrix is None else matrix 94 self._scale = scale 95 self._rotation = rotation
Create a new transformer.
Arguments:
- matrix: Starting transformation matrix.
- scale: Starting overall scale.
- rotation: Starting overall rotation.
97 def translate(self, x: float, y: float): 98 """Apply a translation to the current transformation matrix. 99 100 Args: 101 x: By how much to offset the horizontal coordinate. 102 y: By how much to offset the vertical coordinate. 103 """ 104 transformation = numpy.identity(3) 105 transformation[0][2] = x 106 transformation[1][2] = y 107 self._matrix = numpy.dot(self._matrix, transformation) 108 self._is_default = False
Apply a translation to the current transformation matrix.
Arguments:
- x: By how much to offset the horizontal coordinate.
- y: By how much to offset the vertical coordinate.
110 def scale(self, scale: float): 111 """Apply a scale to the current transformation matrix. 112 113 Args: 114 scale: The scale to apply. 115 """ 116 transformation = numpy.identity(3) 117 transformation[0][0] = scale 118 transformation[1][1] = scale 119 self._matrix = numpy.dot(self._matrix, transformation) 120 self._scale *= scale 121 self._is_default = False
Apply a scale to the current transformation matrix.
Arguments:
- scale: The scale to apply.
123 def rotate(self, angle: float): 124 """Apply a rotation to the current transforation matrix counter-clockwise. 125 126 Args: 127 angle: The angle of rotation to apply as radians. 128 """ 129 cos_angle = math.cos(angle) 130 sin_angle = math.sin(angle) 131 132 transformation = numpy.identity(3) 133 transformation[0][0] = cos_angle 134 transformation[1][1] = cos_angle 135 transformation[1][0] = -1 * sin_angle 136 transformation[0][1] = sin_angle 137 138 self._matrix = numpy.dot(self._matrix, transformation) 139 self._rotation += angle 140 self._is_default = False
Apply a rotation to the current transforation matrix counter-clockwise.
Arguments:
- angle: The angle of rotation to apply as radians.
142 def transform(self, x: float, y: float) -> TransformedPoint: 143 """Transform a point. 144 145 Args: 146 x: The horizontal coordinate to be transformed. 147 y: The vertical coordinate to be transformed. 148 149 Returns: 150 Point after transformation. 151 """ 152 if self._is_default: 153 return TransformedPoint(x, y, self._scale, self._rotation) 154 155 input_array = numpy.array([x, y, 1]) 156 output = numpy.dot(self._matrix, input_array) 157 158 x = output[0] 159 y = output[1] 160 161 return TransformedPoint(x, y, self._scale, self._rotation)
Transform a point.
Arguments:
- x: The horizontal coordinate to be transformed.
- y: The vertical coordinate to be transformed.
Returns:
Point after transformation.
163 def quick_copy(self) -> 'Transformer': 164 """Create a shallow copy of this transformer. 165 166 Returns: 167 Transformer which has the same transform matrix as this original transformer. 168 """ 169 return Transformer(self._matrix, self._scale, self._rotation)
Create a shallow copy of this transformer.
Returns:
Transformer which has the same transform matrix as this original transformer.