33they were vectors. A basic implementation to forgo the need
44to use numpy.
55"""
6- import math
7- import sys
8- from math import sqrt , cos , sin , fabs , atan2
6+ from math import acos , sqrt , cos , sin , fabs , atan2
97
108
119def magnitude (v ):
12- return sqrt (sum (v [i ] * v [i ] for i in range (len (v ))))
10+ """
11+ return: scalar magnitude of vector v
12+ """
13+ return sqrt (sum (c * c for c in v ))
14+
15+
16+ def set_magnitude (v , mag ):
17+ """
18+ return: Vector v with magnitude set to mag.
19+ """
20+ scale = mag / magnitude (v )
21+ return mult (v , scale )
1322
1423
1524def add (u , v ):
16- return [u [ i ] + v [ i ] for i in range ( len ( u ) )]
25+ return [u_i + v_i for u_i , v_i in zip ( u , v )]
1726
1827
1928def sub (u , v ):
20- return [u [i ] - v [i ] for i in range (len (u ))]
29+ return [u_i - v_i for u_i , v_i in zip (u , v )]
30+
31+
32+ def mult (v , s ):
33+ """
34+ Calculate s * v
35+ :param v: Vector.
36+ :param s: Scalar.
37+ :return: [s * v_1, s * v_2, ..., s * v_n]
38+ """
39+ return [c * s for c in v ]
40+
41+
42+ def div (v , s ):
43+ """
44+ Calculate v / s
45+ :param v: Vector.
46+ :param s: Scalar.
47+ :return: [v_1 / s, v_2 / s, ..., v_n / s]
48+ """
49+ return [c / s for c in v ]
2150
2251
2352def dot (u , v ):
24- return sum (u [ i ] * v [ i ] for i in range ( len ( u ) ))
53+ return sum (u_i * v_i for u_i , v_i in zip ( u , v ))
2554
2655
2756def eldiv (u , v ):
28- return [u [ i ] / v [ i ] for i in range ( len ( u ) )]
57+ return [u_i / v_i for u_i , v_i in zip ( u , v )]
2958
3059
3160def elmult (u , v ):
32- return [u [ i ] * v [ i ] for i in range ( len ( u ) )]
61+ return [u_i * v_i for u_i , v_i in zip ( u , v )]
3362
3463
3564def normalize (v ):
36- vmag = magnitude (v )
37- return [v [i ] / vmag for i in range (len (v ))]
65+ return div (v , magnitude (v ))
3866
3967
4068def cross (u , v ):
@@ -45,36 +73,66 @@ def cross(u, v):
4573 return c
4674
4775
48- def mult (u , c ):
49- return [u [i ] * c for i in range (len (u ))]
76+ def scalar_projection (v1 , v2 ):
77+ """
78+ :return: Scalar projection of v1 onto v2.
79+ """
80+ return dot (v1 , normalize (v2 ))
5081
5182
52- def div (u , c ):
53- return [u [i ] / c for i in range (len (u ))]
83+ def projection (v1 , v2 ):
84+ """
85+ Calculate vector projection of v1 on v2
86+ :return: A projection vector.
87+ """
88+ s1 = scalar_projection (v1 , v2 )
89+ return mult (normalize (v2 ), s1 )
5490
5591
56- def quaternion_to_rotation_matrix ( quaternion ):
92+ def rejection ( v1 , v2 ):
5793 """
58- This method takes a quaternion representing a rotation
59- and turns it into a rotation matrix.
60- :return: 3x3 rotation matrix suitable for pre-multiplying vector v:
61- i.e. v' = Mv
94+ Calculate vector rejection of v1 on v2
95+ :return: A rejection vector.
6296 """
63- mag_q = magnitude (quaternion )
64- norm_q = div (quaternion , mag_q )
65- qw , qx , qy , qz = norm_q
66- ww , xx , yy , zz = qw * qw , qx * qx , qy * qy , qz * qz
67- wx , wy , wz , xy , xz , yz = qw * qx , qw * qy , qw * qz , qx * qy , qx * qz , qy * qz
68- # mx = [[qw * qw + qx * qx - qy * qy - qz * qz, 2 * qx * qy - 2 * qw * qz, 2 * qx * qz + 2 * qw * qy],
69- # [2 * qx * qy + 2 * qw * qz, qw * qw - qx * qx + qy * qy - qz * qz, 2 * qy * qz - 2 * qw * qx],
70- # [2 * qx * qz - 2 * qw * qy, 2 * qy * qz + 2 * qw * qx, qw * qw - qx * qx - qy * qy + qz * qz]]
71- # aa, bb, cc, dd = a * a, b * b, c * c, d * d
72- # bc, ad, ac, ab, bd, cd = b * c, a * d, a * c, a * b, b * d, c * d
97+ v1p = projection (v1 , v2 )
98+ return add_vectors ([v1 , v1p ], [1.0 , - 1.0 ])
7399
74- mx = [[ww + xx - yy - zz , 2 * (xy + wz ), 2 * (xz - wy )],
75- [2 * (xy - wz ), ww + yy - xx - zz , 2 * (yz + wx )],
76- [2 * (xz + wy ), 2 * (yz - wx ), ww + zz - xx - yy ]]
77- return mx
100+
101+ def angle (u , v ):
102+ """
103+ Calculate the angle between two non-zero vectors.
104+ :return: The angle between them in radians.
105+ """
106+ d = magnitude (u ) * magnitude (v )
107+ return acos (dot (u , v ) / d )
108+
109+
110+ def add_vectors (vectors , scalars = None ):
111+ """
112+ returns s1*v1+s2*v2+... where scalars = [s1, s2, ...] and vectors=[v1, v2, ...].
113+ :return: Resultant vector
114+ """
115+ if not scalars :
116+ scalars = [1 ] * len (vectors )
117+ else :
118+ assert len (vectors ) == len (scalars )
119+
120+ vector_dimension = len (vectors [0 ])
121+ resultant = [0 ] * vector_dimension
122+ for i , vector in enumerate (vectors ):
123+ resultant = [resultant [c ] + scalars [i ] * vector [c ] for c in range (vector_dimension )]
124+ return resultant
125+
126+
127+ def rotate_vector_around_vector (v , k , a ):
128+ """
129+ Rotate vector v, by an angle a (right-hand rule) in radians around vector k.
130+ :return: rotated vector.
131+ """
132+ k = normalize (k )
133+ vperp = add_vectors ([v , cross (k , v )], [cos (a ), sin (a )])
134+ vparal = mult (k , dot (k , v ) * (1 - cos (a )))
135+ return add_vectors ([vperp , vparal ])
78136
79137
80138def matrix_constant_mult (m , c ):
@@ -100,7 +158,7 @@ def vector_matrix_mult(v, m):
100158 raise ValueError ('vector_matrix_mult mismatched rows' )
101159 columns = len (m [0 ])
102160 result = []
103- for c in range (0 , columns ):
161+ for c in range (columns ):
104162 result .append (sum (v [r ] * m [r ][c ] for r in range (rows )))
105163 return result
106164
@@ -132,15 +190,16 @@ def matrix_inv(a):
132190 """
133191 Invert a square matrix by compouting the determinant and cofactor matrix.
134192 """
193+ len_a = len (a )
135194 det = matrix_det (a )
136195
137- if len ( a ) == 2 :
196+ if len_a == 2 :
138197 return matrix_constant_mult ([[a [1 ][1 ], - 1 * a [0 ][1 ]], [- 1 * a [1 ][0 ], a [0 ][0 ]]], 1 / det )
139198
140199 cofactor = []
141- for r in range (len ( a ) ):
200+ for r in range (len_a ):
142201 row = []
143- for c in range (len ( a ) ):
202+ for c in range (len_a ):
144203 minor = matrix_minor (a , r , c )
145204 row .append (((- 1 ) ** (r + c )) * matrix_det (minor ))
146205 cofactor .append (row )
@@ -151,7 +210,7 @@ def matrix_inv(a):
151210
152211def identity_matrix (size ):
153212 """
154- Create an identity matrix of size size.
213+ Create an identity matrix of size x size.
155214 """
156215 identity = []
157216 for r in range (size ):
@@ -165,18 +224,31 @@ def identity_matrix(size):
165224
166225
167226def transpose (a ):
168- if sys .version_info < (3 , 0 ):
169- return map (list , zip (* a ))
170227 return list (map (list , zip (* a )))
171228
172229
173- def angle ( u , v ):
230+ def quaternion_to_rotation_matrix ( quaternion ):
174231 """
175- Calculate the angle between two non-zero vectors.
176- :return: The angle between them in radians.
232+ This method takes a quaternion representing a rotation
233+ and turns it into a rotation matrix.
234+ :return: 3x3 rotation matrix suitable for pre-multiplying vector v:
235+ i.e. v' = Mv
177236 """
178- d = magnitude (u ) * magnitude (v )
179- return math .acos (dot (u , v ) / d )
237+ mag_q = magnitude (quaternion )
238+ norm_q = div (quaternion , mag_q )
239+ qw , qx , qy , qz = norm_q
240+ ww , xx , yy , zz = qw * qw , qx * qx , qy * qy , qz * qz
241+ wx , wy , wz , xy , xz , yz = qw * qx , qw * qy , qw * qz , qx * qy , qx * qz , qy * qz
242+ # mx = [[qw * qw + qx * qx - qy * qy - qz * qz, 2 * qx * qy - 2 * qw * qz, 2 * qx * qz + 2 * qw * qy],
243+ # [2 * qx * qy + 2 * qw * qz, qw * qw - qx * qx + qy * qy - qz * qz, 2 * qy * qz - 2 * qw * qx],
244+ # [2 * qx * qz - 2 * qw * qy, 2 * qy * qz + 2 * qw * qx, qw * qw - qx * qx - qy * qy + qz * qz]]
245+ # aa, bb, cc, dd = a * a, b * b, c * c, d * d
246+ # bc, ad, ac, ab, bd, cd = b * c, a * d, a * c, a * b, b * d, c * d
247+
248+ mx = [[ww + xx - yy - zz , 2 * (xy + wz ), 2 * (xz - wy )],
249+ [2 * (xy - wz ), ww + yy - xx - zz , 2 * (yz + wx )],
250+ [2 * (xz + wy ), 2 * (yz - wx ), ww + zz - xx - yy ]]
251+ return mx
180252
181253
182254def euler_to_rotation_matrix (euler_angles ):
@@ -198,8 +270,10 @@ def euler_to_rotation_matrix(euler_angles):
198270 cos_roll = cos (euler_angles [2 ])
199271 sin_roll = sin (euler_angles [2 ])
200272 mat3x3 = [
201- [cos_azimuth * cos_elevation , cos_azimuth * sin_elevation * sin_roll - sin_azimuth * cos_roll , cos_azimuth * sin_elevation * cos_roll + sin_azimuth * sin_roll ],
202- [sin_azimuth * cos_elevation , sin_azimuth * sin_elevation * sin_roll + cos_azimuth * cos_roll , sin_azimuth * sin_elevation * cos_roll - cos_azimuth * sin_roll ],
273+ [cos_azimuth * cos_elevation , cos_azimuth * sin_elevation * sin_roll - sin_azimuth * cos_roll ,
274+ cos_azimuth * sin_elevation * cos_roll + sin_azimuth * sin_roll ],
275+ [sin_azimuth * cos_elevation , sin_azimuth * sin_elevation * sin_roll + cos_azimuth * cos_roll ,
276+ sin_azimuth * sin_elevation * cos_roll - cos_azimuth * sin_roll ],
203277 [- sin_elevation , cos_elevation * sin_roll , cos_elevation * cos_roll ]]
204278 return mat3x3
205279
0 commit comments