simetri.graphics.affine

Transformation matrices.

  1"""Transformation matrices."""
  2
  3from math import cos, sin, tan
  4from typing import Sequence, Union
  5
  6import numpy as np
  7
  8from .common import Line, Point
  9from ..geometry.geometry import line_angle, vec_along_line, is_line, is_point
 10
 11
 12def identity_matrix() -> 'ndarray':
 13    """
 14    Return the identity matrix
 15    [[1.0, 0, 0], [0, 1.0, 0], [0, 0, 1.0]].
 16
 17    Returns:
 18        np.ndarray: The identity matrix.
 19    """
 20    return np.identity(3)
 21
 22
 23def xform_matrix(
 24    a: float, b: float, c: float, d: float, e: float, f: float
 25) -> 'ndarray':
 26    """
 27    Return a transformation matrix in row form
 28    [[a, b, 0], [c, d, 0], [e, f, 1.0]].
 29
 30    Args:
 31        a (float): The a component of the transformation matrix.
 32        b (float): The b component of the transformation matrix.
 33        c (float): The c component of the transformation matrix.
 34        d (float): The d component of the transformation matrix.
 35        e (float): The e component of the transformation matrix.
 36        f (float): The f component of the transformation matrix.
 37
 38    Returns:
 39        np.ndarray: The transformation matrix.
 40    """
 41    return np.array([[a, b, 0], [c, d, 0], [e, f, 1.0]])
 42
 43
 44def translation_matrix(dx: float, dy: float) -> 'ndarray':
 45    """
 46    Return a translation matrix in row form
 47    [[1.0, 0, 0], [0, 1.0, 0], [dx, dy, 1.0]].
 48
 49    Args:
 50        dx (float): The translation distance along the x-axis.
 51        dy (float): The translation distance along the y-axis.
 52
 53    Returns:
 54        np.ndarray: The translation matrix.
 55    """
 56    return np.array([[1.0, 0, 0], [0, 1.0, 0], [dx, dy, 1.0]])
 57
 58
 59def inv_translation_matrix(dx: float, dy: float) -> 'ndarray':
 60    """
 61    Return the inverse of a translation matrix in row form
 62    [[1.0, 0, 0], [0, 1.0, 0], [-dx, -dy, 1.0]].
 63
 64    Args:
 65        dx (float): The translation distance along the x-axis.
 66        dy (float): The translation distance along the y-axis.
 67
 68    Returns:
 69        np.ndarray: The inverse translation matrix.
 70    """
 71    return np.array([[1.0, 0, 0], [0, 1.0, 0], [-dx, -dy, 1.0]])
 72
 73
 74def rot_about_origin_matrix(theta: float) -> 'ndarray':
 75    """
 76    Return a rotation matrix in row form
 77    [[cos(theta), sin(theta), 0], [-sin(theta), cos(theta), 0], [0, 0, 1.0]].
 78
 79    Args:
 80        theta (float): The rotation angle in radians.
 81
 82    Returns:
 83        np.ndarray: The rotation matrix.
 84    """
 85    c = cos(theta)
 86    s = sin(theta)
 87    return np.array([[c, s, 0], [-s, c, 0], [0, 0, 1.0]])
 88
 89
 90def rotation_matrix(theta: float, about=(0, 0)) -> 'ndarray':
 91    """
 92    Construct a rotation matrix that can be used to rotate a point
 93    about another point by theta float.
 94    Return a rotation matrix in row form
 95    dx, dy = about
 96    [[cos(theta), sin(theta), 0],
 97    [-sin(theta), cos(theta), 0],
 98    cos(theta)dx-sin(theta)dy+x, cos(theta)dy+sin(theta)dx+y, 1]].
 99
100    Args:
101        theta (float): The rotation angle in radians.
102        about (tuple, optional): The point to rotate about, defaults to (0, 0).
103
104    Returns:
105        np.ndarray: The rotation matrix.
106    """
107    dx, dy = about[:2]
108    # translate 'about' to the origin
109    trans_mat = translation_matrix(-dx, -dy)
110    # rotate around the origin
111    rot_mat = rot_about_origin_matrix(theta)
112    # translate it back to initial pos
113    inv_trans_mat = translation_matrix(dx, dy)
114    # compose the transformation matrix
115    return trans_mat @ rot_mat @ inv_trans_mat
116
117
118def inv_rotation_matrix(theta: float, about=(0, 0)) -> 'ndarray':
119    """
120    Construct the inverse of a rotation matrix that can be used to rotate a point
121    about another point by theta float.
122    Return a rotation matrix in row form
123    dx, dy = about
124    [[cos(theta), -sin(theta), 0],
125    [sin(theta), cos(theta), 0],
126    -cos(theta)dx-sin(theta)dy+x, -sin(theta)dx+cos(theta)dy+y, 1]].
127
128    Args:
129        theta (float): The rotation angle in radians.
130        about (tuple, optional): The point to rotate about, defaults to (0, 0).
131
132    Returns:
133        np.ndarray: The inverse rotation matrix.
134    """
135    dx, dy = about[:2]
136    # translate 'about' to the origin
137    trans_mat = translation_matrix(-dx, -dy)
138    # rotate around the origin
139    rot_mat = rot_about_origin_matrix(theta)
140    # translate it back to initial pos
141    inv_trans_mat = translation_matrix(dx, dy)
142    # compose the transformation matrix
143    return inv_trans_mat @ rot_mat.T @ trans_mat
144
145
146def glide_matrix(mirror_line: Line, distance: float) -> 'ndarray':
147    """
148    Return a glide-reflection matrix in row form.
149    Reflect about the given vector then translate by dx
150    along the same vector.
151
152    Args:
153        mirror_line (Line): The line to mirror about.
154        distance (float): The distance to translate along the line.
155
156    Returns:
157        np.ndarray: The glide-reflection matrix.
158    """
159    mirror_mat = mirror_about_line_matrix(mirror_line)
160    x, y = vec_along_line(mirror_line, distance)[:2]
161    trans_mat = translation_matrix(x, y)
162
163    return mirror_mat @ trans_mat
164
165
166def inv_glide_matrix(mirror_line: Line, distance: float) -> 'ndarray':
167    """
168    Return the inverse of a glide-reflection matrix in row form.
169    Reflect about the given vector then translate by dx
170    along the same vector.
171
172    Args:
173        mirror_line (Line): The line to mirror about.
174        distance (float): The distance to translate along the line.
175
176    Returns:
177        np.ndarray: The inverse glide-reflection matrix.
178    """
179    mirror_mat = mirror_about_line_matrix(mirror_line)
180    x, y = vec_along_line(mirror_line, distance)[:2]
181    trans_matrix = translation_matrix(x, y)
182
183    return trans_matrix @ mirror_mat
184
185
186def scale_matrix(scale_x: float, scale_y: float = None) -> 'ndarray':
187    """
188    Return a scale matrix in row form.
189
190    Args:
191        scale_x (float): Scale factor in x direction.
192        scale_y (float, optional): Scale factor in y direction, defaults to None.
193
194    Returns:
195        np.ndarray: A scale matrix in row form.
196    """
197    if scale_y is None:
198        scale_y = scale_x
199    return np.array([[scale_x, 0, 0], [0, scale_y, 0], [0, 0, 1.0]])
200
201
202def inv_scale_matrix(scale_x: float, scale_y: float = None) -> 'ndarray':
203    """
204    Return the inverse of a scale matrix in row form.
205
206    Args:
207        scale_x (float): Scale factor in x direction.
208        scale_y (float, optional): Scale factor in y direction, defaults to None.
209
210    Returns:
211        np.ndarray: The inverse of a scale matrix in row form.
212    """
213    if scale_y is None:
214        scale_y = scale_x
215    return np.array([[1 / scale_x, 0, 0], [0, 1 / scale_y, 0], [0, 0, 1.0]])
216
217
218def scale_in_place_matrix(scale_x: float, scale_y: float, about: Point) -> 'ndarray':
219    """
220    Return a scale matrix in row form that scales about a point.
221
222    Args:
223        scale_x (float): Scale factor in x direction.
224        scale_y (float): Scale factor in y direction.
225        about (Point): Point about which the scaling is performed.
226
227    Returns:
228        np.ndarray: A scale matrix in row form that scales about a point.
229    """
230    dx, dy = about[:2]
231    trans_mat = translation_matrix(-dx, -dy)
232    scale_mat = np.array([[scale_x, 0, 0], [0, scale_y, 0], [0, 0, 1.0]])
233    inv_trans_mat = translation_matrix(dx, dy)
234    return trans_mat @ scale_mat @ inv_trans_mat
235
236
237def shear_matrix(theta_x: float, theta_y: float = 0) -> 'ndarray':
238    """
239    Return a shear matrix in row form.
240
241    Args:
242        theta_x (float): Angle of shear in x direction.
243        theta_y (float, optional): Angle of shear in y direction, defaults to 0.
244
245    Returns:
246        np.ndarray: A shear matrix in row form.
247    """
248    return np.array([[1, tan(theta_y), 0], [tan(theta_x), 1, 0], [0, 0, 1.0]])
249
250
251def inv_shear_matrix(theta_x: float, theta_y: float = 0) -> 'ndarray':
252    """
253    Return the inverse of a shear matrix in row form.
254
255    Args:
256        theta_x (float): Angle of shear in x direction.
257        theta_y (float, optional): Angle of shear in y direction, defaults to 0.
258
259    Returns:
260        np.ndarray: The inverse of a shear matrix in row form.
261    """
262    return np.array([[1, -tan(theta_x), 0], [-tan(theta_y), 1, 0], [0, 0, 1.0]])
263
264
265def mirror_matrix(about: Union[Line, Point]) -> 'ndarray':
266    """
267    Return a matrix to perform reflection about a line or a point.
268
269    Args:
270        about (Union[Line, Point]): A line or point about which the reflection is performed.
271
272    Returns:
273        np.ndarray: A matrix to perform reflection about a line or a point.
274
275    Raises:
276        RuntimeError: If about is not a line or a point.
277    """
278    if is_line(about):
279        res = mirror_about_line_matrix(about)
280    elif is_point(about):
281        res = mirror_about_point_matrix(about)
282    else:
283        raise RuntimeError(f"{about} is invalid!")
284    return res
285
286
287def mirror_about_x_matrix() -> 'ndarray':
288    """
289    Return a matrix to perform reflection about the x-axis.
290
291    Returns:
292        np.ndarray: A matrix to perform reflection about the x-axis.
293    """
294    return np.array([[1.0, 0, 0], [0, -1.0, 0], [0, 0, 1.0]])
295
296
297def mirror_about_y_matrix() -> 'ndarray':
298    """
299    Return a matrix to perform reflection about the y-axis.
300
301    Returns:
302        np.ndarray: A matrix to perform reflection about the y-axis.
303    """
304    return np.array([[-1.0, 0, 0], [0, 1.0, 0], [0, 0, 1.0]])
305
306
307def mirror_about_line_matrix(line: Line) -> 'ndarray':
308    """
309    Return a matrix to perform reflection about a line.
310
311    Args:
312        line (Line): The line about which the reflection is performed.
313
314    Returns:
315        np.ndarray: A matrix to perform reflection about a line.
316    """
317    p1, p2 = line
318    x1, y1 = p1[:2]
319    theta = line_angle(p1, p2)
320    two_theta = 2 * theta
321
322    # translate the line to the origin
323    # T = translation_matrix(-x1, -y1)
324    # rotate about the origin by 2*theta
325    # R = rot_about_origin_matrix(2*theta)
326    # translate back
327    # inv_t = translation_matrix(x1, y1)
328    # return T @ R @ inv_t
329
330    # We precompute the matrix
331    c2 = cos(two_theta)
332    s2 = sin(two_theta)
333    return np.array(
334        [
335            [c2, s2, 0],
336            [s2, -c2, 0],
337            [-x1 * c2 + x1 - y1 * s2, -x1 * s2 + y1 * c2 + y1, 1.0],
338        ]
339    )
340
341
342def mirror_about_origin_matrix() -> 'ndarray':
343    """
344    Return a matrix to perform reflection about the origin.
345
346    Returns:
347        np.ndarray: A matrix to perform reflection about the origin.
348    """
349    return np.array([[-1.0, 0, 0], [0, -1.0, 0], [0, 0, 1.0]])
350
351
352def mirror_about_point_matrix(point: Point) -> 'ndarray':
353    """
354    Return a matrix to perform reflection about a point.
355
356    Args:
357        point (Point): The point about which the reflection is performed.
358
359    Returns:
360        np.ndarray: A matrix to perform reflection about a point.
361    """
362    x, y = point[:2]
363    # T = translation_matrix(-x, -y)
364    # M = mirror_about_origin_matrix()
365    # inv_t = translation_matrix(x, y)
366    # return T @ M @ inv_t
367    # We precompute the matrix
368
369    return np.array([[-1.0, 0, 0], [0, -1.0, 0], [2 * x, 2 * y, 1.0]])
370
371
372def rotate(points: Sequence[Point], theta: float, about: Point = (0, 0)) -> 'ndarray':
373    """
374    Rotate points by theta about a point.
375
376    Args:
377        points (Sequence[Point]): The points to rotate.
378        theta (float): The angle to rotate by.
379        about (Point, optional): The point to rotate about, defaults to (0, 0).
380
381    Returns:
382        np.ndarray: The rotated points.
383    """
384    return points @ rotation_matrix(theta, about)
385
386
387def translate(points: Sequence[Point], dx: float, dy: float) -> 'ndarray':
388    """
389    Translate points by dx, dy.
390
391    Args:
392        points (Sequence[Point]): The points to translate.
393        dx (float): The translation distance along the x-axis.
394        dy (float): The translation distance along the y-axis.
395
396    Returns:
397        np.ndarray: The translated points.
398    """
399    return points @ translation_matrix(dx, dy)
400
401
402def mirror(points: Sequence[Point], about: Line) -> 'ndarray':
403    """
404    Mirror points about a line.
405
406    Args:
407        points (Sequence[Point]): The points to mirror.
408        about (Line): The line to mirror about.
409
410    Returns:
411        np.ndarray: The mirrored points.
412    """
413    return points @ mirror_matrix(about)
414
415
416def glide(points: Sequence[Point], mirror_line: Line, distance: float) -> 'ndarray':
417    """
418    Glide (mirror about a line then translate along the same line) points about a line.
419
420    Args:
421        points (Sequence[Point]): The points to glide.
422        mirror_line (Line): The line to mirror about.
423        distance (float): The distance to translate along the line.
424
425    Returns:
426        np.ndarray: The glided points.
427    """
428    return points @ glide_matrix(mirror_line, distance)
429
430
431def shear(points: Sequence[Point], theta_x: float, theta_y: float = 0) -> 'ndarray':
432    """
433    Shear points by theta_x in x direction and theta_y in y direction.
434
435    Args:
436        points (Sequence[Point]): The points to shear.
437        theta_x (float): The angle of shear in x direction.
438        theta_y (float, optional): The angle of shear in y direction, defaults to 0.
439
440    Returns:
441        np.ndarray: The sheared points.
442    """
443    return points @ shear_matrix(theta_x, theta_y)
444
445
446def scale(points: Sequence[Point], scale_x: float, scale_y: float) -> 'ndarray':
447    """
448    Scale points by scale_x in x direction and scale_y in y direction.
449
450    Args:
451        points (Sequence[Point]): The points to scale.
452        scale_x (float): The scale factor in x direction.
453        scale_y (float): The scale factor in y direction.
454
455    Returns:
456        np.ndarray: The scaled points.
457    """
458    return points @ scale_matrix(scale_x, scale_y)
459
460
461def scale_in_place(
462    points: Sequence[Point], scale_x: float, scale_y: float, about: Point
463) -> 'ndarray':
464    """
465    Scale points about a point by scale_x in x direction and scale_y in y direction.
466
467    Args:
468        points (Sequence[Point]): The points to scale.
469        scale_x (float): The scale factor in x direction.
470        scale_y (float): The scale factor in y direction.
471        about (Point): The point about which the scaling is performed.
472
473    Returns:
474        np.ndarray: The scaled points.
475    """
476    return points @ scale_in_place_matrix(scale_x, scale_y, about)
def identity_matrix() -> 'ndarray':
13def identity_matrix() -> 'ndarray':
14    """
15    Return the identity matrix
16    [[1.0, 0, 0], [0, 1.0, 0], [0, 0, 1.0]].
17
18    Returns:
19        np.ndarray: The identity matrix.
20    """
21    return np.identity(3)

Return the identity matrix [[1.0, 0, 0], [0, 1.0, 0], [0, 0, 1.0]].

Returns:

np.ndarray: The identity matrix.

def xform_matrix(a: float, b: float, c: float, d: float, e: float, f: float) -> 'ndarray':
24def xform_matrix(
25    a: float, b: float, c: float, d: float, e: float, f: float
26) -> 'ndarray':
27    """
28    Return a transformation matrix in row form
29    [[a, b, 0], [c, d, 0], [e, f, 1.0]].
30
31    Args:
32        a (float): The a component of the transformation matrix.
33        b (float): The b component of the transformation matrix.
34        c (float): The c component of the transformation matrix.
35        d (float): The d component of the transformation matrix.
36        e (float): The e component of the transformation matrix.
37        f (float): The f component of the transformation matrix.
38
39    Returns:
40        np.ndarray: The transformation matrix.
41    """
42    return np.array([[a, b, 0], [c, d, 0], [e, f, 1.0]])

Return a transformation matrix in row form [[a, b, 0], [c, d, 0], [e, f, 1.0]].

Arguments:
  • a (float): The a component of the transformation matrix.
  • b (float): The b component of the transformation matrix.
  • c (float): The c component of the transformation matrix.
  • d (float): The d component of the transformation matrix.
  • e (float): The e component of the transformation matrix.
  • f (float): The f component of the transformation matrix.
Returns:

np.ndarray: The transformation matrix.

def translation_matrix(dx: float, dy: float) -> 'ndarray':
45def translation_matrix(dx: float, dy: float) -> 'ndarray':
46    """
47    Return a translation matrix in row form
48    [[1.0, 0, 0], [0, 1.0, 0], [dx, dy, 1.0]].
49
50    Args:
51        dx (float): The translation distance along the x-axis.
52        dy (float): The translation distance along the y-axis.
53
54    Returns:
55        np.ndarray: The translation matrix.
56    """
57    return np.array([[1.0, 0, 0], [0, 1.0, 0], [dx, dy, 1.0]])

Return a translation matrix in row form [[1.0, 0, 0], [0, 1.0, 0], [dx, dy, 1.0]].

Arguments:
  • dx (float): The translation distance along the x-axis.
  • dy (float): The translation distance along the y-axis.
Returns:

np.ndarray: The translation matrix.

def inv_translation_matrix(dx: float, dy: float) -> 'ndarray':
60def inv_translation_matrix(dx: float, dy: float) -> 'ndarray':
61    """
62    Return the inverse of a translation matrix in row form
63    [[1.0, 0, 0], [0, 1.0, 0], [-dx, -dy, 1.0]].
64
65    Args:
66        dx (float): The translation distance along the x-axis.
67        dy (float): The translation distance along the y-axis.
68
69    Returns:
70        np.ndarray: The inverse translation matrix.
71    """
72    return np.array([[1.0, 0, 0], [0, 1.0, 0], [-dx, -dy, 1.0]])

Return the inverse of a translation matrix in row form [[1.0, 0, 0], [0, 1.0, 0], [-dx, -dy, 1.0]].

Arguments:
  • dx (float): The translation distance along the x-axis.
  • dy (float): The translation distance along the y-axis.
Returns:

np.ndarray: The inverse translation matrix.

def rot_about_origin_matrix(theta: float) -> 'ndarray':
75def rot_about_origin_matrix(theta: float) -> 'ndarray':
76    """
77    Return a rotation matrix in row form
78    [[cos(theta), sin(theta), 0], [-sin(theta), cos(theta), 0], [0, 0, 1.0]].
79
80    Args:
81        theta (float): The rotation angle in radians.
82
83    Returns:
84        np.ndarray: The rotation matrix.
85    """
86    c = cos(theta)
87    s = sin(theta)
88    return np.array([[c, s, 0], [-s, c, 0], [0, 0, 1.0]])

Return a rotation matrix in row form [[cos(theta), sin(theta), 0], [-sin(theta), cos(theta), 0], [0, 0, 1.0]].

Arguments:
  • theta (float): The rotation angle in radians.
Returns:

np.ndarray: The rotation matrix.

def rotation_matrix(theta: float, about=(0, 0)) -> 'ndarray':
 91def rotation_matrix(theta: float, about=(0, 0)) -> 'ndarray':
 92    """
 93    Construct a rotation matrix that can be used to rotate a point
 94    about another point by theta float.
 95    Return a rotation matrix in row form
 96    dx, dy = about
 97    [[cos(theta), sin(theta), 0],
 98    [-sin(theta), cos(theta), 0],
 99    cos(theta)dx-sin(theta)dy+x, cos(theta)dy+sin(theta)dx+y, 1]].
100
101    Args:
102        theta (float): The rotation angle in radians.
103        about (tuple, optional): The point to rotate about, defaults to (0, 0).
104
105    Returns:
106        np.ndarray: The rotation matrix.
107    """
108    dx, dy = about[:2]
109    # translate 'about' to the origin
110    trans_mat = translation_matrix(-dx, -dy)
111    # rotate around the origin
112    rot_mat = rot_about_origin_matrix(theta)
113    # translate it back to initial pos
114    inv_trans_mat = translation_matrix(dx, dy)
115    # compose the transformation matrix
116    return trans_mat @ rot_mat @ inv_trans_mat

Construct a rotation matrix that can be used to rotate a point about another point by theta float. Return a rotation matrix in row form dx, dy = about [[cos(theta), sin(theta), 0], [-sin(theta), cos(theta), 0], cos(theta)dx-sin(theta)dy+x, cos(theta)dy+sin(theta)dx+y, 1]].

Arguments:
  • theta (float): The rotation angle in radians.
  • about (tuple, optional): The point to rotate about, defaults to (0, 0).
Returns:

np.ndarray: The rotation matrix.

def inv_rotation_matrix(theta: float, about=(0, 0)) -> 'ndarray':
119def inv_rotation_matrix(theta: float, about=(0, 0)) -> 'ndarray':
120    """
121    Construct the inverse of a rotation matrix that can be used to rotate a point
122    about another point by theta float.
123    Return a rotation matrix in row form
124    dx, dy = about
125    [[cos(theta), -sin(theta), 0],
126    [sin(theta), cos(theta), 0],
127    -cos(theta)dx-sin(theta)dy+x, -sin(theta)dx+cos(theta)dy+y, 1]].
128
129    Args:
130        theta (float): The rotation angle in radians.
131        about (tuple, optional): The point to rotate about, defaults to (0, 0).
132
133    Returns:
134        np.ndarray: The inverse rotation matrix.
135    """
136    dx, dy = about[:2]
137    # translate 'about' to the origin
138    trans_mat = translation_matrix(-dx, -dy)
139    # rotate around the origin
140    rot_mat = rot_about_origin_matrix(theta)
141    # translate it back to initial pos
142    inv_trans_mat = translation_matrix(dx, dy)
143    # compose the transformation matrix
144    return inv_trans_mat @ rot_mat.T @ trans_mat

Construct the inverse of a rotation matrix that can be used to rotate a point about another point by theta float. Return a rotation matrix in row form dx, dy = about [[cos(theta), -sin(theta), 0], [sin(theta), cos(theta), 0], -cos(theta)dx-sin(theta)dy+x, -sin(theta)dx+cos(theta)dy+y, 1]].

Arguments:
  • theta (float): The rotation angle in radians.
  • about (tuple, optional): The point to rotate about, defaults to (0, 0).
Returns:

np.ndarray: The inverse rotation matrix.

def glide_matrix(mirror_line: Sequence[Sequence], distance: float) -> 'ndarray':
147def glide_matrix(mirror_line: Line, distance: float) -> 'ndarray':
148    """
149    Return a glide-reflection matrix in row form.
150    Reflect about the given vector then translate by dx
151    along the same vector.
152
153    Args:
154        mirror_line (Line): The line to mirror about.
155        distance (float): The distance to translate along the line.
156
157    Returns:
158        np.ndarray: The glide-reflection matrix.
159    """
160    mirror_mat = mirror_about_line_matrix(mirror_line)
161    x, y = vec_along_line(mirror_line, distance)[:2]
162    trans_mat = translation_matrix(x, y)
163
164    return mirror_mat @ trans_mat

Return a glide-reflection matrix in row form. Reflect about the given vector then translate by dx along the same vector.

Arguments:
  • mirror_line (Line): The line to mirror about.
  • distance (float): The distance to translate along the line.
Returns:

np.ndarray: The glide-reflection matrix.

def inv_glide_matrix(mirror_line: Sequence[Sequence], distance: float) -> 'ndarray':
167def inv_glide_matrix(mirror_line: Line, distance: float) -> 'ndarray':
168    """
169    Return the inverse of a glide-reflection matrix in row form.
170    Reflect about the given vector then translate by dx
171    along the same vector.
172
173    Args:
174        mirror_line (Line): The line to mirror about.
175        distance (float): The distance to translate along the line.
176
177    Returns:
178        np.ndarray: The inverse glide-reflection matrix.
179    """
180    mirror_mat = mirror_about_line_matrix(mirror_line)
181    x, y = vec_along_line(mirror_line, distance)[:2]
182    trans_matrix = translation_matrix(x, y)
183
184    return trans_matrix @ mirror_mat

Return the inverse of a glide-reflection matrix in row form. Reflect about the given vector then translate by dx along the same vector.

Arguments:
  • mirror_line (Line): The line to mirror about.
  • distance (float): The distance to translate along the line.
Returns:

np.ndarray: The inverse glide-reflection matrix.

def scale_matrix(scale_x: float, scale_y: float = None) -> 'ndarray':
187def scale_matrix(scale_x: float, scale_y: float = None) -> 'ndarray':
188    """
189    Return a scale matrix in row form.
190
191    Args:
192        scale_x (float): Scale factor in x direction.
193        scale_y (float, optional): Scale factor in y direction, defaults to None.
194
195    Returns:
196        np.ndarray: A scale matrix in row form.
197    """
198    if scale_y is None:
199        scale_y = scale_x
200    return np.array([[scale_x, 0, 0], [0, scale_y, 0], [0, 0, 1.0]])

Return a scale matrix in row form.

Arguments:
  • scale_x (float): Scale factor in x direction.
  • scale_y (float, optional): Scale factor in y direction, defaults to None.
Returns:

np.ndarray: A scale matrix in row form.

def inv_scale_matrix(scale_x: float, scale_y: float = None) -> 'ndarray':
203def inv_scale_matrix(scale_x: float, scale_y: float = None) -> 'ndarray':
204    """
205    Return the inverse of a scale matrix in row form.
206
207    Args:
208        scale_x (float): Scale factor in x direction.
209        scale_y (float, optional): Scale factor in y direction, defaults to None.
210
211    Returns:
212        np.ndarray: The inverse of a scale matrix in row form.
213    """
214    if scale_y is None:
215        scale_y = scale_x
216    return np.array([[1 / scale_x, 0, 0], [0, 1 / scale_y, 0], [0, 0, 1.0]])

Return the inverse of a scale matrix in row form.

Arguments:
  • scale_x (float): Scale factor in x direction.
  • scale_y (float, optional): Scale factor in y direction, defaults to None.
Returns:

np.ndarray: The inverse of a scale matrix in row form.

def scale_in_place_matrix(scale_x: float, scale_y: float, about: Sequence[float]) -> 'ndarray':
219def scale_in_place_matrix(scale_x: float, scale_y: float, about: Point) -> 'ndarray':
220    """
221    Return a scale matrix in row form that scales about a point.
222
223    Args:
224        scale_x (float): Scale factor in x direction.
225        scale_y (float): Scale factor in y direction.
226        about (Point): Point about which the scaling is performed.
227
228    Returns:
229        np.ndarray: A scale matrix in row form that scales about a point.
230    """
231    dx, dy = about[:2]
232    trans_mat = translation_matrix(-dx, -dy)
233    scale_mat = np.array([[scale_x, 0, 0], [0, scale_y, 0], [0, 0, 1.0]])
234    inv_trans_mat = translation_matrix(dx, dy)
235    return trans_mat @ scale_mat @ inv_trans_mat

Return a scale matrix in row form that scales about a point.

Arguments:
  • scale_x (float): Scale factor in x direction.
  • scale_y (float): Scale factor in y direction.
  • about (Point): Point about which the scaling is performed.
Returns:

np.ndarray: A scale matrix in row form that scales about a point.

def shear_matrix(theta_x: float, theta_y: float = 0) -> 'ndarray':
238def shear_matrix(theta_x: float, theta_y: float = 0) -> 'ndarray':
239    """
240    Return a shear matrix in row form.
241
242    Args:
243        theta_x (float): Angle of shear in x direction.
244        theta_y (float, optional): Angle of shear in y direction, defaults to 0.
245
246    Returns:
247        np.ndarray: A shear matrix in row form.
248    """
249    return np.array([[1, tan(theta_y), 0], [tan(theta_x), 1, 0], [0, 0, 1.0]])

Return a shear matrix in row form.

Arguments:
  • theta_x (float): Angle of shear in x direction.
  • theta_y (float, optional): Angle of shear in y direction, defaults to 0.
Returns:

np.ndarray: A shear matrix in row form.

def inv_shear_matrix(theta_x: float, theta_y: float = 0) -> 'ndarray':
252def inv_shear_matrix(theta_x: float, theta_y: float = 0) -> 'ndarray':
253    """
254    Return the inverse of a shear matrix in row form.
255
256    Args:
257        theta_x (float): Angle of shear in x direction.
258        theta_y (float, optional): Angle of shear in y direction, defaults to 0.
259
260    Returns:
261        np.ndarray: The inverse of a shear matrix in row form.
262    """
263    return np.array([[1, -tan(theta_x), 0], [-tan(theta_y), 1, 0], [0, 0, 1.0]])

Return the inverse of a shear matrix in row form.

Arguments:
  • theta_x (float): Angle of shear in x direction.
  • theta_y (float, optional): Angle of shear in y direction, defaults to 0.
Returns:

np.ndarray: The inverse of a shear matrix in row form.

def mirror_matrix(about: Union[Sequence[Sequence], Sequence[float]]) -> 'ndarray':
266def mirror_matrix(about: Union[Line, Point]) -> 'ndarray':
267    """
268    Return a matrix to perform reflection about a line or a point.
269
270    Args:
271        about (Union[Line, Point]): A line or point about which the reflection is performed.
272
273    Returns:
274        np.ndarray: A matrix to perform reflection about a line or a point.
275
276    Raises:
277        RuntimeError: If about is not a line or a point.
278    """
279    if is_line(about):
280        res = mirror_about_line_matrix(about)
281    elif is_point(about):
282        res = mirror_about_point_matrix(about)
283    else:
284        raise RuntimeError(f"{about} is invalid!")
285    return res

Return a matrix to perform reflection about a line or a point.

Arguments:
  • about (Union[Line, Point]): A line or point about which the reflection is performed.
Returns:

np.ndarray: A matrix to perform reflection about a line or a point.

Raises:
  • RuntimeError: If about is not a line or a point.
def mirror_about_x_matrix() -> 'ndarray':
288def mirror_about_x_matrix() -> 'ndarray':
289    """
290    Return a matrix to perform reflection about the x-axis.
291
292    Returns:
293        np.ndarray: A matrix to perform reflection about the x-axis.
294    """
295    return np.array([[1.0, 0, 0], [0, -1.0, 0], [0, 0, 1.0]])

Return a matrix to perform reflection about the x-axis.

Returns:

np.ndarray: A matrix to perform reflection about the x-axis.

def mirror_about_y_matrix() -> 'ndarray':
298def mirror_about_y_matrix() -> 'ndarray':
299    """
300    Return a matrix to perform reflection about the y-axis.
301
302    Returns:
303        np.ndarray: A matrix to perform reflection about the y-axis.
304    """
305    return np.array([[-1.0, 0, 0], [0, 1.0, 0], [0, 0, 1.0]])

Return a matrix to perform reflection about the y-axis.

Returns:

np.ndarray: A matrix to perform reflection about the y-axis.

def mirror_about_line_matrix(line: Sequence[Sequence]) -> 'ndarray':
308def mirror_about_line_matrix(line: Line) -> 'ndarray':
309    """
310    Return a matrix to perform reflection about a line.
311
312    Args:
313        line (Line): The line about which the reflection is performed.
314
315    Returns:
316        np.ndarray: A matrix to perform reflection about a line.
317    """
318    p1, p2 = line
319    x1, y1 = p1[:2]
320    theta = line_angle(p1, p2)
321    two_theta = 2 * theta
322
323    # translate the line to the origin
324    # T = translation_matrix(-x1, -y1)
325    # rotate about the origin by 2*theta
326    # R = rot_about_origin_matrix(2*theta)
327    # translate back
328    # inv_t = translation_matrix(x1, y1)
329    # return T @ R @ inv_t
330
331    # We precompute the matrix
332    c2 = cos(two_theta)
333    s2 = sin(two_theta)
334    return np.array(
335        [
336            [c2, s2, 0],
337            [s2, -c2, 0],
338            [-x1 * c2 + x1 - y1 * s2, -x1 * s2 + y1 * c2 + y1, 1.0],
339        ]
340    )

Return a matrix to perform reflection about a line.

Arguments:
  • line (Line): The line about which the reflection is performed.
Returns:

np.ndarray: A matrix to perform reflection about a line.

def mirror_about_origin_matrix() -> 'ndarray':
343def mirror_about_origin_matrix() -> 'ndarray':
344    """
345    Return a matrix to perform reflection about the origin.
346
347    Returns:
348        np.ndarray: A matrix to perform reflection about the origin.
349    """
350    return np.array([[-1.0, 0, 0], [0, -1.0, 0], [0, 0, 1.0]])

Return a matrix to perform reflection about the origin.

Returns:

np.ndarray: A matrix to perform reflection about the origin.

def mirror_about_point_matrix(point: Sequence[float]) -> 'ndarray':
353def mirror_about_point_matrix(point: Point) -> 'ndarray':
354    """
355    Return a matrix to perform reflection about a point.
356
357    Args:
358        point (Point): The point about which the reflection is performed.
359
360    Returns:
361        np.ndarray: A matrix to perform reflection about a point.
362    """
363    x, y = point[:2]
364    # T = translation_matrix(-x, -y)
365    # M = mirror_about_origin_matrix()
366    # inv_t = translation_matrix(x, y)
367    # return T @ M @ inv_t
368    # We precompute the matrix
369
370    return np.array([[-1.0, 0, 0], [0, -1.0, 0], [2 * x, 2 * y, 1.0]])

Return a matrix to perform reflection about a point.

Arguments:
  • point (Point): The point about which the reflection is performed.
Returns:

np.ndarray: A matrix to perform reflection about a point.

def rotate( points: Sequence[Sequence[float]], theta: float, about: Sequence[float] = (0, 0)) -> 'ndarray':
373def rotate(points: Sequence[Point], theta: float, about: Point = (0, 0)) -> 'ndarray':
374    """
375    Rotate points by theta about a point.
376
377    Args:
378        points (Sequence[Point]): The points to rotate.
379        theta (float): The angle to rotate by.
380        about (Point, optional): The point to rotate about, defaults to (0, 0).
381
382    Returns:
383        np.ndarray: The rotated points.
384    """
385    return points @ rotation_matrix(theta, about)

Rotate points by theta about a point.

Arguments:
  • points (Sequence[Point]): The points to rotate.
  • theta (float): The angle to rotate by.
  • about (Point, optional): The point to rotate about, defaults to (0, 0).
Returns:

np.ndarray: The rotated points.

def translate(points: Sequence[Sequence[float]], dx: float, dy: float) -> 'ndarray':
388def translate(points: Sequence[Point], dx: float, dy: float) -> 'ndarray':
389    """
390    Translate points by dx, dy.
391
392    Args:
393        points (Sequence[Point]): The points to translate.
394        dx (float): The translation distance along the x-axis.
395        dy (float): The translation distance along the y-axis.
396
397    Returns:
398        np.ndarray: The translated points.
399    """
400    return points @ translation_matrix(dx, dy)

Translate points by dx, dy.

Arguments:
  • points (Sequence[Point]): The points to translate.
  • dx (float): The translation distance along the x-axis.
  • dy (float): The translation distance along the y-axis.
Returns:

np.ndarray: The translated points.

def mirror( points: Sequence[Sequence[float]], about: Sequence[Sequence]) -> 'ndarray':
403def mirror(points: Sequence[Point], about: Line) -> 'ndarray':
404    """
405    Mirror points about a line.
406
407    Args:
408        points (Sequence[Point]): The points to mirror.
409        about (Line): The line to mirror about.
410
411    Returns:
412        np.ndarray: The mirrored points.
413    """
414    return points @ mirror_matrix(about)

Mirror points about a line.

Arguments:
  • points (Sequence[Point]): The points to mirror.
  • about (Line): The line to mirror about.
Returns:

np.ndarray: The mirrored points.

def glide( points: Sequence[Sequence[float]], mirror_line: Sequence[Sequence], distance: float) -> 'ndarray':
417def glide(points: Sequence[Point], mirror_line: Line, distance: float) -> 'ndarray':
418    """
419    Glide (mirror about a line then translate along the same line) points about a line.
420
421    Args:
422        points (Sequence[Point]): The points to glide.
423        mirror_line (Line): The line to mirror about.
424        distance (float): The distance to translate along the line.
425
426    Returns:
427        np.ndarray: The glided points.
428    """
429    return points @ glide_matrix(mirror_line, distance)

Glide (mirror about a line then translate along the same line) points about a line.

Arguments:
  • points (Sequence[Point]): The points to glide.
  • mirror_line (Line): The line to mirror about.
  • distance (float): The distance to translate along the line.
Returns:

np.ndarray: The glided points.

def shear( points: Sequence[Sequence[float]], theta_x: float, theta_y: float = 0) -> 'ndarray':
432def shear(points: Sequence[Point], theta_x: float, theta_y: float = 0) -> 'ndarray':
433    """
434    Shear points by theta_x in x direction and theta_y in y direction.
435
436    Args:
437        points (Sequence[Point]): The points to shear.
438        theta_x (float): The angle of shear in x direction.
439        theta_y (float, optional): The angle of shear in y direction, defaults to 0.
440
441    Returns:
442        np.ndarray: The sheared points.
443    """
444    return points @ shear_matrix(theta_x, theta_y)

Shear points by theta_x in x direction and theta_y in y direction.

Arguments:
  • points (Sequence[Point]): The points to shear.
  • theta_x (float): The angle of shear in x direction.
  • theta_y (float, optional): The angle of shear in y direction, defaults to 0.
Returns:

np.ndarray: The sheared points.

def scale( points: Sequence[Sequence[float]], scale_x: float, scale_y: float) -> 'ndarray':
447def scale(points: Sequence[Point], scale_x: float, scale_y: float) -> 'ndarray':
448    """
449    Scale points by scale_x in x direction and scale_y in y direction.
450
451    Args:
452        points (Sequence[Point]): The points to scale.
453        scale_x (float): The scale factor in x direction.
454        scale_y (float): The scale factor in y direction.
455
456    Returns:
457        np.ndarray: The scaled points.
458    """
459    return points @ scale_matrix(scale_x, scale_y)

Scale points by scale_x in x direction and scale_y in y direction.

Arguments:
  • points (Sequence[Point]): The points to scale.
  • scale_x (float): The scale factor in x direction.
  • scale_y (float): The scale factor in y direction.
Returns:

np.ndarray: The scaled points.

def scale_in_place( points: Sequence[Sequence[float]], scale_x: float, scale_y: float, about: Sequence[float]) -> 'ndarray':
462def scale_in_place(
463    points: Sequence[Point], scale_x: float, scale_y: float, about: Point
464) -> 'ndarray':
465    """
466    Scale points about a point by scale_x in x direction and scale_y in y direction.
467
468    Args:
469        points (Sequence[Point]): The points to scale.
470        scale_x (float): The scale factor in x direction.
471        scale_y (float): The scale factor in y direction.
472        about (Point): The point about which the scaling is performed.
473
474    Returns:
475        np.ndarray: The scaled points.
476    """
477    return points @ scale_in_place_matrix(scale_x, scale_y, about)

Scale points about a point by scale_x in x direction and scale_y in y direction.

Arguments:
  • points (Sequence[Point]): The points to scale.
  • scale_x (float): The scale factor in x direction.
  • scale_y (float): The scale factor in y direction.
  • about (Point): The point about which the scaling is performed.
Returns:

np.ndarray: The scaled points.