77# --------------------------- Matrix routines -------------------------
88#
99# This will be our first example of making a .py file that is imported into the jupyter notebook/other .py file
10- # This is so that the basic matrix functions - making matrices, checking them, plotting - can be in one place.
10+ # This is so that the basic matrix functions - making matrices, checking them, plotting - can be in one place,
11+ # the re-used in multiple places using "import".
1112#
1213# The code is organized as
1314# Making scaling, rotation, translation matrices
@@ -29,11 +30,12 @@ def make_scale_matrix(scale_x=1.0, scale_y=1.0):
2930 @param scale_x - scale in x. Should NOT be 0.0
3031 @param scale_y - scale in y. Should NOT be 0.0
3132 @returns a 3x3 scaling matrix"""
33+ # Throw an error if a zero scale
3234 if np .isclose (scale_x , 0.0 ) or np .isclose (scale_y , 0.0 ):
3335 raise ValueError (f"Scale values should be non_zero { scale_x } , { scale_y } " )
3436
3537 # Set the diagonal elements to the scale values
36- mat = np .identity (3 )
38+ mat = np .identity (3 ) # Always use identity to make the initial 3x3 matrix
3739 mat [0 , 0 ] = scale_x
3840 mat [1 , 1 ] = scale_y
3941
@@ -46,7 +48,7 @@ def make_translation_matrix(d_x=0.0, d_y=0.0):
4648 @param d_y - translate in y
4749 @returns a 3x3 translation matrix"""
4850
49- # Set the last column to the amount to move
51+ # Set the last column to be the amount to move
5052 mat = np .identity (3 )
5153 mat [0 , 2 ] = d_x
5254 mat [1 , 2 ] = d_y
@@ -60,6 +62,7 @@ def make_rotation_matrix(theta=0.0):
6062 @param theta - rotate by theta (theta in radians)
6163 @returns a 3x3 rotation matrix"""
6264
65+ # If you multiply [x y 1]^t by the matrix, this is what you get
6366 # x rotated = cos(theta) * x - sin(theta) * y
6467 # y rotated = sin(theta) * x + cos(theta) * y
6568 mat = np .identity (3 )
@@ -74,21 +77,22 @@ def make_rotation_matrix(theta=0.0):
7477# ------------------------------- What kind of matrix is it? What does it do? -------------------------------------
7578
7679def get_dx_dy_from_matrix (mat ):
77- """Where does the matrix translate 0,0 to?
80+ """Where does the matrix translate 0, 0 to?
7881 @param mat - the matrix
7982 @returns dx, dy - the transformed point 0,0"""
8083
81- # Don 't forget to turn origin into a homogenous point...
84+ # Create a point for the origin (0,0) ... don 't forget that the 3rd component should be 1
8285 # Multiply the origin by the matrix then return the x and y components
8386 # Reminder: @ is the matrix multiplication
8487 origin = np .zeros (shape = (3 ,))
8588 origin [2 ] = 1.0
8689
87- xy_one = mat @ origin
88- return xy_one [0 ], xy_one [1 ]
90+ xy_ret = mat @ origin
91+ # Ditch the 1 at the end and return a tuple (x,y)
92+ return xy_ret [0 ], xy_ret [1 ]
8993
9094
91- # Doing this one in two pieces - first, get out how the axes (1,0) and (0,1) are transformed, then in the mext
95+ # Doing this one in two pieces - first, get out how the axes (1,0) and (0,1) are transformed, then in the next
9296# method get theta out of how (1,0) is transformed
9397def get_axes_from_matrix (mat ):
9498 """Where does the matrix rotate (1,0) (0,1) to?
@@ -99,14 +103,16 @@ def get_axes_from_matrix(mat):
99103 # 1) Set x_axis to be a unit vector pointing down the x axis
100104 # 2) Set y_axis to be a unit vector pointing down the y axis
101105 # Multiply by the matrix to get the new "x" and "y" axes
106+ # Reminder: zeros in the third row, not ones, because vectors can't translate
102107 x_axis = np .zeros (shape = (3 ,))
103108 y_axis = np .zeros (shape = (3 ,))
104109
105- x_axis [0 ] = 1.0
106- y_axis [1 ] = 1.0
110+ x_axis [0 ] = 1.0 # 1, 0, 0
111+ y_axis [1 ] = 1.0 # 0, 1, 0
107112
108113 x_axis_rotated = mat @ x_axis
109114 y_axis_rotated = mat @ y_axis
115+ # Get out the first two values. This is a tuple with a 2 dimensional array for each vector
110116 return x_axis_rotated [0 :2 ], y_axis_rotated [0 :2 ]
111117
112118
@@ -119,7 +125,9 @@ def get_theta_from_matrix(mat):
119125 # Step 2) use arctan2 to turn the rotated x axis vector into an angle
120126 # Use the x axis because theta for the x axis is 0 (makes the math easier)
121127 # Reminder: arctan2 takes (y, x)
122- x_axis_rotated , _ = get_axes_from_matrix (mat )
128+ x_axis_rotated , _ = get_axes_from_matrix (mat ) # The _ says ignore the second returned vector
129+
130+ # arctan2 takes y, x and returns the angle in the range -pi to pi
123131 theta = np .arctan2 (x_axis_rotated [1 ], x_axis_rotated [0 ])
124132 return theta
125133
@@ -133,8 +141,11 @@ def plot_pts(axs, pts, fmt='-k'):
133141 @param fmt - optional format parameter"""
134142
135143 # This gets the x values (in row 0) and the y values and just does a regular plot
144+ #
136145 axs .plot (pts [0 , :], pts [1 , :], fmt )
137146
147+ # We have to do this get the line to go from the last point to the first
148+ # (Not necessary if you duplicate the first point as the last point in pts)
138149 pts_close = np .zeros ((2 , 2 ))
139150 pts_close [:, 0 ] = pts [0 :2 , 0 ]
140151 pts_close [:, 1 ] = pts [0 :2 , - 1 ]
@@ -168,25 +179,32 @@ def plot_transformed_axes(axs, mat):
168179 axs .arrow (x = origin_moved [0 ], y = origin_moved [1 ], dx = y_axis_moved [0 ], dy = y_axis_moved [1 ], color = 'blue' , linestyle = "--" )
169180
170181
171- def plot_axes_and_big_box (axs ):
182+ def plot_axes_and_big_box (axs , box_size = 5 ):
172183 """Plot the origin and x,y axes with a box at -5, -5 to 5, 5
173184 @param axs - figure axes"""
174185
175186 # Put a black + at the origin
176187 axs .plot (0 , 0 , '+k' )
188+
189+ arrow_length = 1.0
190+ if box_size < 1.0 :
191+ arrow_length = box_size * 0.9
177192 # Draw one red arrow for the x axis (x,y, dx, dy)
178- axs .arrow (x = 0 , y = 0 , dx = 1 , dy = 0 , color = 'red' )
193+ axs .arrow (x = 0 , y = 0 , dx = arrow_length , dy = 0 , color = 'red' )
179194 # Draw a blue arrow for the y axis
180- axs .arrow (x = 0 , y = 0 , dx = 0 , dy = 1 , color = 'blue' )
195+ axs .arrow (x = 0 , y = 0 , dx = 0 , dy = arrow_length , color = 'blue' )
181196
182197 # Draw a box around the world to make sure the plots stay the same size
183- axs .plot ([- 5 , 5 , 5 , - 5 , - 5 ], [- 5 , - 5 , 5 , 5 , - 5 ], '-k' )
198+ axs .plot ([- box_size , box_size , box_size , - box_size , - box_size ], [- box_size , - box_size , box_size , box_size , - box_size ], '-k' )
184199
185200 # This makes sure the x and y axes are scaled the same
186201 axs .axis ('equal' )
187202
188203
189204
205+ """ Everything after __name__ is NOT imported when you import matrix_routines.py. However, if you run
206+ this file - by using the triangle in the upper right - this code will get executed. It's usually used
207+ to hold test code"""
190208if __name__ == '__main__' :
191209 # Create a matrix that has one of each type and call the plot code
192210 fig , axs = plt .subplots (1 , 1 , figsize = (6 , 3 ))
@@ -210,6 +228,9 @@ def plot_axes_and_big_box(axs):
210228
211229 # Depending on if your mac, windows, linux, and if interactive is true, you may need to call this to get the plt
212230 # windows to show
231+
213232 plt .show ()
233+
234+ # If it exits on you then put a break point at the line below and run in the debugger
214235 print ("Done" )
215236
0 commit comments