Add brief license headers to tests
[blender.git] / tests / python / bl_pyapi_mathutils.py
1 # Apache License, Version 2.0
2
3 # ./blender.bin --background -noaudio --python tests/python/bl_pyapi_mathutils.py
4 import unittest
5 from test import support
6 from mathutils import Matrix, Vector
7 from mathutils import kdtree
8 import math
9
10 # keep globals immutable
11 vector_data = (
12     (1.0, 0.0, 0.0),
13     (0.0, 1.0, 0.0),
14     (0.0, 0.0, 1.0),
15
16     (1.0, 1.0, 1.0),
17
18     (0.33783, 0.715698, -0.611206),
19     (-0.944031, -0.326599, -0.045624),
20     (-0.101074, -0.416443, -0.903503),
21     (0.799286, 0.49411, -0.341949),
22     (-0.854645, 0.518036, 0.033936),
23     (0.42514, -0.437866, -0.792114),
24     (-0.358948, 0.597046, 0.717377),
25     (-0.985413,0.144714, 0.089294),
26     )
27
28 # get data at different scales
29 vector_data = sum(
30     (tuple(tuple(a * scale for a in v) for v in vector_data)
31     for scale in (s * sign for s in (0.0001, 0.1, 1.0, 10.0, 1000.0, 100000.0)
32                            for sign in (1.0, -1.0))), ()) + ((0.0, 0.0, 0.0),)
33
34
35 class MatrixTesting(unittest.TestCase):
36     def test_matrix_column_access(self):
37         #mat =
38         #[ 1  2  3  4 ]
39         #[ 1  2  3  4 ]
40         #[ 1  2  3  4 ]
41         mat = Matrix(((1, 11, 111),
42                       (2, 22, 222),
43                       (3, 33, 333),
44                       (4, 44, 444)))
45
46         self.assertEqual(mat[0], Vector((1, 11, 111)))
47         self.assertEqual(mat[1], Vector((2, 22, 222)))
48         self.assertEqual(mat[2], Vector((3, 33, 333)))
49         self.assertEqual(mat[3], Vector((4, 44, 444)))
50
51     def test_item_access(self):
52         args = ((1, 4, 0, -1),
53                 (2, -1, 2, -2),
54                 (0, 3, 8, 3),
55                 (-2, 9, 1, 0))
56
57         mat = Matrix(args)
58
59         for row in range(4):
60             for col in range(4):
61                 self.assertEqual(mat[row][col], args[row][col])
62
63         self.assertEqual(mat[0][2], 0)
64         self.assertEqual(mat[3][1], 9)
65         self.assertEqual(mat[2][3], 3)
66         self.assertEqual(mat[0][0], 1)
67         self.assertEqual(mat[3][3], 0)
68
69     def test_item_assignment(self):
70         mat = Matrix() - Matrix()
71         indices = (0, 0), (1, 3), (2, 0), (3, 2), (3, 1)
72         checked_indices = []
73         for row, col in indices:
74             mat[row][col] = 1
75
76         for row in range(4):
77             for col in range(4):
78                 if mat[row][col]:
79                     checked_indices.append((row, col))
80
81         for item in checked_indices:
82             self.assertIn(item, indices)
83
84     def test_matrix_to_3x3(self):
85         #mat =
86         #[ 1  2  3  4  ]
87         #[ 2  4  6  8  ]
88         #[ 3  6  9  12 ]
89         #[ 4  8  12 16 ]
90         mat = Matrix(tuple((i, 2 * i, 3 * i, 4 * i) for i in range(1, 5)))
91         mat_correct = Matrix(((1, 2, 3), (2, 4, 6), (3, 6, 9)))
92         self.assertEqual(mat.to_3x3(), mat_correct)
93
94     def test_matrix_to_translation(self):
95         mat = Matrix()
96         mat[0][3] = 1
97         mat[1][3] = 2
98         mat[2][3] = 3
99         self.assertEqual(mat.to_translation(), Vector((1, 2, 3)))
100
101     def test_matrix_translation(self):
102         mat = Matrix()
103         mat.translation = Vector((1, 2, 3))
104         self.assertEqual(mat[0][3], 1)
105         self.assertEqual(mat[1][3], 2)
106         self.assertEqual(mat[2][3], 3)
107
108     def test_non_square_mult(self):
109         mat1 = Matrix(((1, 2, 3),
110                        (4, 5, 6)))
111         mat2 = Matrix(((1, 2),
112                        (3, 4),
113                        (5, 6)))
114
115         prod_mat1 = Matrix(((22, 28),
116                             (49, 64)))
117         prod_mat2 = Matrix(((9, 12, 15),
118                             (19, 26, 33),
119                             (29, 40, 51)))
120
121         self.assertEqual(mat1 * mat2, prod_mat1)
122         self.assertEqual(mat2 * mat1, prod_mat2)
123
124     def test_mat4x4_vec3D_mult(self):
125         mat = Matrix(((1, 0, 2, 0),
126                       (0, 6, 0, 0),
127                       (0, 0, 1, 1),
128                       (0, 0, 0, 1)))
129
130         vec = Vector((1, 2, 3))
131         
132         prod_mat_vec = Vector((7, 12, 4))
133         prod_vec_mat = Vector((1, 12, 5))
134
135         self.assertEqual(mat * vec, prod_mat_vec)
136         self.assertEqual(vec * mat, prod_vec_mat)
137
138     def test_mat_vec_mult(self):
139         mat1 = Matrix()
140
141         vec = Vector((1, 2))
142
143         self.assertRaises(ValueError, mat1.__mul__, vec)
144         self.assertRaises(ValueError, vec.__mul__, mat1)
145
146         mat2 = Matrix(((1, 2),
147                        (-2, 3)))
148
149         prod = Vector((5, 4))
150
151         self.assertEqual(mat2 * vec, prod)
152
153     def test_matrix_inverse(self):
154         mat = Matrix(((1, 4, 0, -1),
155                       (2, -1, 2, -2),
156                       (0, 3, 8, 3),
157                       (-2, 9, 1, 0)))
158
159         inv_mat = (1 / 285) * Matrix(((195, -57, 27, -102),
160                                       (50, -19, 4, 6),
161                                       (-60, 57, 18, 27),
162                                       (110, -133, 43, -78)))
163
164         self.assertEqual(mat.inverted(), inv_mat)
165
166     def test_matrix_mult(self):
167         mat = Matrix(((1, 4, 0, -1),
168                       (2, -1, 2, -2),
169                       (0, 3, 8, 3),
170                       (-2, 9, 1, 0)))
171
172         prod_mat = Matrix(((11, -9, 7, -9),
173                            (4, -3, 12, 6),
174                            (0, 48, 73, 18),
175                            (16, -14, 26, -13)))
176
177         self.assertEqual(mat * mat, prod_mat)
178
179
180 class VectorTesting(unittest.TestCase):
181
182     def test_orthogonal(self):
183
184         angle_90d = math.pi / 2.0
185         for v in vector_data:
186             v = Vector(v)
187             if v.length_squared != 0.0:
188                 self.assertAlmostEqual(v.angle(v.orthogonal()), angle_90d)
189
190
191 class KDTreeTesting(unittest.TestCase):
192
193     @staticmethod
194     def kdtree_create_grid_3d(tot):
195         k = kdtree.KDTree(tot * tot * tot)
196         index = 0
197         mul = 1.0 / (tot - 1)
198         for x in range(tot):
199             for y in range(tot):
200                 for z in range(tot):
201                     k.insert((x * mul, y * mul, z * mul), index)
202                     index += 1
203         k.balance()
204         return k
205
206     def test_kdtree_single(self):
207         co = (0,) * 3
208         index = 2
209
210         k = kdtree.KDTree(1)
211         k.insert(co, index)
212         k.balance()
213
214         co_found, index_found, dist_found = k.find(co)
215
216         self.assertEqual(tuple(co_found), co)
217         self.assertEqual(index_found, index)
218         self.assertEqual(dist_found, 0.0)
219
220     def test_kdtree_empty(self):
221         co = (0,) * 3
222
223         k = kdtree.KDTree(0)
224         k.balance()
225
226         co_found, index_found, dist_found = k.find(co)
227
228         self.assertIsNone(co_found)
229         self.assertIsNone(index_found)
230         self.assertIsNone(dist_found)
231
232     def test_kdtree_line(self):
233         tot = 10
234
235         k = kdtree.KDTree(tot)
236
237         for i in range(tot):
238             k.insert((i,) * 3, i)
239
240         k.balance()
241
242         co_found, index_found, dist_found = k.find((-1,) * 3)
243         self.assertEqual(tuple(co_found), (0,) * 3)
244
245         co_found, index_found, dist_found = k.find((tot,) * 3)
246         self.assertEqual(tuple(co_found), (tot - 1,) * 3)
247
248     def test_kdtree_grid(self):
249         size = 10
250         k = self.kdtree_create_grid_3d(size)
251
252         # find_range
253         ret = k.find_range((0.5,) * 3, 2.0)
254         self.assertEqual(len(ret), size * size * size)
255
256         ret = k.find_range((1.0,) * 3, 1.0 / size)
257         self.assertEqual(len(ret), 1)
258
259         ret = k.find_range((1.0,) * 3, 2.0 / size)
260         self.assertEqual(len(ret), 8)
261
262         ret = k.find_range((10,) * 3, 0.5)
263         self.assertEqual(len(ret), 0)
264
265         # find_n
266         tot = 0
267         ret = k.find_n((1.0,) * 3, tot)
268         self.assertEqual(len(ret), tot)
269
270         tot = 10
271         ret = k.find_n((1.0,) * 3, tot)
272         self.assertEqual(len(ret), tot)
273         self.assertEqual(ret[0][2], 0.0)
274
275         tot = size * size * size
276         ret = k.find_n((1.0,) * 3, tot)
277         self.assertEqual(len(ret), tot)
278
279     def test_kdtree_invalid_size(self):
280         with self.assertRaises(ValueError):
281             kdtree.KDTree(-1)
282
283     def test_kdtree_invalid_balance(self):
284         co = (0,) * 3
285         index = 2
286
287         k = kdtree.KDTree(2)
288         k.insert(co, index)
289         k.balance()
290         k.insert(co, index)
291         with self.assertRaises(RuntimeError):
292             k.find(co)
293
294
295 def test_main():
296     try:
297         support.run_unittest(MatrixTesting)
298         support.run_unittest(VectorTesting)
299         support.run_unittest(KDTreeTesting)
300     except:
301         import traceback
302         traceback.print_exc()
303
304         # alert CTest we failed
305         import sys
306         sys.exit(1)
307
308 if __name__ == '__main__':
309     test_main()