1
2 from util import format_number
3 from vector3 import Vector3
4
5 from math import sin, cos, tan, sqrt, pi, radians
6
7
8
9
11
12 """Matrix44 Exception class"""
13
15 Exception.__init__(self)
16 self.code = code
17 self.description = description
18
20 return "%s (%s)" % (self.description, self.code)
21
22
24
25 """Represents the contents of a row when accessed through a property.
26
27 """
28
29 _type_error = "A vector type must be used to do math on rows"
30
31
37
43
49
55
56
60
61
63
64 _identity = ( (1.0, 0.0, 0.0, 0.0),
65 (0.0, 1.0, 0.0, 0.0),
66 (0.0, 0.0, 1.0, 0.0),
67 (0.0, 0.0, 0.0, 1.0) )
68
69 __slots__ = ('_m',)
70
72
73 """If no parameteres are given, the Matrix44 is initialised to identity.
74 If 1 parameter is given it should be an iterable with the 16 components
75 of the matrix.
76 If 4 parameters are given they should be 4 sequences of up to 4 values.
77 Missing values in each row are padded out with values from the identity matix
78 (so you can use Vector3's or tuples of 3 values).
79
80 """
81
82
83 if not args:
84 self._m = [1.,0.,0.,0., 0.,1.,0.,0., 0.,0.,1.,0., 0.,0.,0.,1.]
85 return
86
87
88 elif len(args) == 4:
89 self._m = [1.,0.,0.,0., 0.,1.,0.,0., 0.,0.,1.,0., 0.,0.,0.,1.]
90
91 row_0, row_1, row_2, row_3 = self._setters
92 r1, r2, r3, r4 = args
93
94 row_0(self, r1)
95 row_1(self, r2)
96 row_2(self, r3)
97 row_3(self, r4)
98
99 else:
100 raise TypeError("Matrix44.__init__() takes 0, or 4 arguments (%i given)"%len(args))
101
102
104 return Row(self._m[0:4])
105
107 return Row(self._m[4:8])
108
110 return Row(self._m[8:12])
111
113 return Row(self._m[12:16])
114
116 values = tuple(values)[:4]
117 self._m[0:len(values)] = map(float, values)
118
120 values = tuple(values)[:4]
121 self._m[4:4+len(values)] = map(float, values)
122
124 values = tuple(values)[:4]
125 self._m[8:8+len(values)] = map(float, values)
126
128 values = tuple(values)[:4]
129 self._m[12:12+len(values)] = map(float, values)
130
131 _getters = (_get_row_0, _get_row_1, _get_row_2, _get_row_3)
132 _setters = (_set_row_0, _set_row_1, _set_row_2, _set_row_3)
133
134 _row0 = property(_get_row_0, _set_row_0, None, "Row 0")
135 _row1 = property(_get_row_1, _set_row_1, None, "Row 1")
136 _row2 = property(_get_row_2, _set_row_2, None, "Row 2")
137 _row3 = property(_get_row_3, _set_row_3, None, "Row 3")
138
139 x_axis = _row0
140 right = _row0
141 y_axis = _row1
142 up = _row1
143 z_axis = _row2
144 forward = _row2
145 translate = _row3
146
147
149
150 """Converts the matrix in to a list of values, suitable for using
151 with glLoadMatrix*
152
153 """
154
155 return self._m[:]
156
157
158 - def set(self, row1, row2, row3, row4):
159
160 """Sets all four rows of the matrix,
161
162 @type row1: sequence
163 @param row1: First row
164 @type row2: sequence
165 @param row2: Second row
166 @type row3: sequence
167 @param row3: Third row
168 @type row4: sequence
169 @param row4: Fourth row
170 @return: None
171
172 """
173
174 set_row_0, set_row_1, set_row_2, set_row_3 = self._setters
175
176 set_row_0(self, row1)
177 set_row_1(self, row2)
178 set_row_2(self, row3)
179 set_row_3(self, row4)
180
181
183 """Gets a row of the matrix as a tuple
184
185 row_no -- Index of row
186
187 """
188 try:
189 return self._getters[row_no](self)
190 except IndexError:
191 raise IndexError("Row must be 0, 1, 2 or 3")
192
193
194 @classmethod
196 """Creates a Matrix44 from an iterable of 16 values."""
197
198 m = cls.__new__(cls, object)
199 m._m = map(float, iterable)
200 if len(m._m) != 16:
201 raise ValueError("Iterable must have 16 values")
202 return m
203
204
205 @classmethod
206 - def clone(cls, copy_Matrix44):
207 """Creates a Matrix44 that is a copy of another."""
208
209 m = cls.__new__(cls, object)
210 m._m = copy_Matrix44._m[:]
211 return m
212
213
214 @classmethod
216 """Creates a blank Matrix44 (with no information). This is rarely
217 required, you may want to use an identity Matrix44,
218 see Matrix44.identity()
219
220 """
221
222 m = cls.__new__(cls, object)
223 m._m = [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,]
224 return m
225
226
227 @classmethod
229 """Creates and identity Matrix44."""
230
231 m = cls.__new__(cls, object)
232 m._m = [1., 0., 0., 0., 0., 1., 0., 0., 0., 0., 1., 0., 0., 0., 0., 1.]
233 return m
234
235
236 @classmethod
237 - def scale(cls, scale_x, scale_y= None, scale_z= None):
238 """Creates a scale Matrix44.
239 If one parameter is given the scale is uniform,
240 if three parameters are give the scale is different (potentialy) on each x axis.
241
242 """
243
244 m = cls.__new__(cls, object)
245 return m.make_scale(scale_x, scale_y, scale_z)
246
247
248 @classmethod
250 """Creates a translation Matrix44 to (x, y, z).
251
252 x -- X Coordinate
253 y -- Y Coordinate
254 z -- Z Coordinate
255
256 """
257
258 m = cls.__new__(cls, object)
259 return m.make_translation(x, y, z)
260
261
262 @classmethod
264 """Creates a Matrix44 that does a rotation about the x axis.
265
266 angle -- Angle of rotation (in radians)
267
268 """
269
270 m = cls.__new__(cls, object)
271 return m.make_x_rotation(angle)
272
273
274 @classmethod
276 """Creates a Matrix44 that does a rotation about the y axis.
277
278 angle -- Angle of rotation (in radians)
279
280 """
281
282 m = cls.__new__(cls, object)
283 return m.make_y_rotation(angle)
284
285
286 @classmethod
288 """Creates a Matrix44 that does a rotation about the z axis.
289
290 angle -- Angle of rotation (in radians)
291
292 """
293
294 m = cls.__new__(cls, object)
295 return m.make_z_rotation(angle)
296
297
298 @classmethod
300 """Creates a Matrix44 that does a rotation about an axis.
301
302 axis -- A vector of the axis
303 angle -- Angle of rotation
304
305 """
306
307 m = cls.__new__(cls, object)
308 return m.make_rotation_about_axis(axis, angle)
309
310
311 @classmethod
313 """Creates a Matrix44 that does a rotation about each axis.
314
315 angle_x -- Angle of rotation, about x
316 angle_y -- Angle of rotation, about y
317 angle_z -- Angle of rotation, about z
318
319 """
320
321 m = cls.__new__(cls, object)
322 return m.make_xyz_rotation(angle_x, angle_y, angle_z)
323
324
325 @classmethod
327 """Creates a Matrix44 that projects points in to 2d space.
328
329 left -- Coordinate of left of screen
330 right -- Coordination of right of screen
331 top -- Coordination of the top of the screen
332 bottom -- Coordination of the borrom of the screen
333 near -- Coordination of the near clipping plane
334 far -- Coordinate of the far clipping plane
335
336 """
337
338 m = cls.__new__(cls, object)
339 return m.make_perspective_projection( left,
340 right,
341 top,
342 bottom,
343 near,
344 far)
345
346
347 @classmethod
349 """Creates a Matrix44 that projects points in to 2d space
350
351 fov -- The field of view (in radians)
352 aspect -- The aspect ratio of the screen (width / height)
353 near -- Coordinate of the near clipping plane
354 far -- Coordinate of the far clipping plane
355
356 """
357
358 m = cls.__new__(cls, object)
359 return m.make_perspective_projection_fov(fov, aspect, near, far)
360
361
363 """'Pretty' formatting of the Matrix44."""
364
365
366
367
368
369 cols = [ map(format_number, col) for col in self.columns() ]
370
371 def decimal_pos(n):
372 if '.' in n:
373 return n.index('.')
374 return len(n)
375
376 for col_no, col in enumerate(cols[:]):
377
378 decimal = max( decimal_pos(format_number(c)) for c in col )
379 cols[col_no] = [" "*(decimal-decimal_pos(c))+c for c in col]
380
381 max_col_lengths = [ max(len(c) for c in col) for col in cols ]
382 rows = [[], [], [], []]
383 for row_no in xrange(4):
384
385 for col_no in xrange(4):
386
387 v = cols[col_no][row_no]
388 rows[row_no].append( v.ljust(max_col_lengths[col_no]) )
389
390 rows = [" ".join(row).rstrip() for row in rows]
391 return "\n".join("[ %s ]"%row for row in rows)
392
393 return str(cols)
394
395
397
398 def format_row(row):
399 return "(%s)" % ", ".join( format_number(value) for value in row )
400
401 return "Matrix44(%s)" % \
402 ", ".join(format_row(row) for row in self.rows())
403
404
406
407 """Allows matrices to be used as keys in a dictionary."""
408
409 return hash(tuple(self._m))
410
411
413 """Sets an individual element in the Matrix44.
414 coord is a tuple of (row, column)
415
416 eg. Matrix44[2,3] = 3.
417
418 """
419
420 try:
421 row, col = coord
422 self._m[row * 4 + col] = 1.0 * value
423 except IndexError:
424 raise IndexError( "Row and Column should be 0, 1, 2 or 3" )
425 except TypeError:
426 raise TypeError( "Must be a number" )
427
428
430 """Gets an individual element in the Matrix44.
431 coord is a tuple of (row, column)
432
433 eg. print Matrix44[2,3]
434
435 """
436
437 try:
438 row, col = coord
439 return self._m[row * 4 + col]
440 except IndexError:
441 raise IndexError( "Row and Column should be 0, 1, 2 or 3" )
442 except TypeError:
443 raise TypeError( "index should be two values containing"\
444 " the row and column" )
445
446
448 """Iterates over all 16 values in the Matrix44."""
449
450 return iter(self._m[:])
451
452
454 """Returns the inverse of the matrix."""
455
456 return self.get_inverse()
457
458
460 """Returns the result of multiplying this Matrix44 by another, called
461 by the * (multiply) operator."""
462
463 m1_0, m1_1, m1_2, m1_3, \
464 m1_4, m1_5, m1_6, m1_7, \
465 m1_8, m1_9, m1_10, m1_11, \
466 m1_12, m1_13, m1_14, m1_15 = self._m
467
468 m2_0, m2_1, m2_2, m2_3, \
469 m2_4, m2_5, m2_6, m2_7, \
470 m2_8, m2_9, m2_10, m2_11, \
471 m2_12, m2_13, m2_14, m2_15 = rhs._m
472
473 retm = [ m2_0 * m1_0 + m2_1 * m1_4 + m2_2 * m1_8 + m2_3 * m1_12,
474 m2_0 * m1_1 + m2_1 * m1_5 + m2_2 * m1_9 + m2_3 * m1_13,
475 m2_0 * m1_2 + m2_1 * m1_6 + m2_2 * m1_10 + m2_3 * m1_14,
476 m2_0 * m1_3 + m2_1 * m1_7 + m2_2 * m1_11 + m2_3 * m1_15,
477
478 m2_4 * m1_0 + m2_5 * m1_4 + m2_6 * m1_8 + m2_7 * m1_12,
479 m2_4 * m1_1 + m2_5 * m1_5 + m2_6 * m1_9 + m2_7 * m1_13,
480 m2_4 * m1_2 + m2_5 * m1_6 + m2_6 * m1_10 + m2_7 * m1_14,
481 m2_4 * m1_3 + m2_5 * m1_7 + m2_6 * m1_11 + m2_7 * m1_15,
482
483 m2_8 * m1_0 + m2_9 * m1_4 + m2_10 * m1_8 + m2_11 * m1_12,
484 m2_8 * m1_1 + m2_9 * m1_5 + m2_10 * m1_9 + m2_11 * m1_13,
485 m2_8 * m1_2 + m2_9 * m1_6 + m2_10 * m1_10 + m2_11 * m1_14,
486 m2_8 * m1_3 + m2_9 * m1_7 + m2_10 * m1_11 + m2_11 * m1_15,
487
488 m2_12 * m1_0 + m2_13 * m1_4 + m2_14 * m1_8 + m2_15 * m1_12,
489 m2_12 * m1_1 + m2_13 * m1_5 + m2_14 * m1_9 + m2_15 * m1_13,
490 m2_12 * m1_2 + m2_13 * m1_6 + m2_14 * m1_10 + m2_15 * m1_14,
491 m2_12 * m1_3 + m2_13 * m1_7 + m2_14 * m1_11 + m2_15 * m1_15 ]
492
493 ret = self.__new__(self.__class__, object)
494 ret._m = retm
495
496 return ret
497
498
500
501 """Multiplies this Matrix44 by another, called by the *= operator."""
502
503 m1_0, m1_1, m1_2, m1_3, \
504 m1_4, m1_5, m1_6, m1_7, \
505 m1_8, m1_9, m1_10, m1_11, \
506 m1_12, m1_13, m1_14, m1_15 = self._m
507
508 m2_0, m2_1, m2_2, m2_3, \
509 m2_4, m2_5, m2_6, m2_7, \
510 m2_8, m2_9, m2_10, m2_11, \
511 m2_12, m2_13, m2_14, m2_15 = rhs._m
512
513
514 self._m = [ m2_0 * m1_0 + m2_1 * m1_4 + m2_2 * m1_8 + m2_3 * m1_12,
515 m2_0 * m1_1 + m2_1 * m1_5 + m2_2 * m1_9 + m2_3 * m1_13,
516 m2_0 * m1_2 + m2_1 * m1_6 + m2_2 * m1_10 + m2_3 * m1_14,
517 m2_0 * m1_3 + m2_1 * m1_7 + m2_2 * m1_11 + m2_3 * m1_15,
518
519 m2_4 * m1_0 + m2_5 * m1_4 + m2_6 * m1_8 + m2_7 * m1_12,
520 m2_4 * m1_1 + m2_5 * m1_5 + m2_6 * m1_9 + m2_7 * m1_13,
521 m2_4 * m1_2 + m2_5 * m1_6 + m2_6 * m1_10 + m2_7 * m1_14,
522 m2_4 * m1_3 + m2_5 * m1_7 + m2_6 * m1_11 + m2_7 * m1_15,
523
524 m2_8 * m1_0 + m2_9 * m1_4 + m2_10 * m1_8 + m2_11 * m1_12,
525 m2_8 * m1_1 + m2_9 * m1_5 + m2_10 * m1_9 + m2_11 * m1_13,
526 m2_8 * m1_2 + m2_9 * m1_6 + m2_10 * m1_10 + m2_11 * m1_14,
527 m2_8 * m1_3 + m2_9 * m1_7 + m2_10 * m1_11 + m2_11 * m1_15,
528
529 m2_12 * m1_0 + m2_13 * m1_4 + m2_14 * m1_8 + m2_15 * m1_12,
530 m2_12 * m1_1 + m2_13 * m1_5 + m2_14 * m1_9 + m2_15 * m1_13,
531 m2_12 * m1_2 + m2_13 * m1_6 + m2_14 * m1_10 + m2_15 * m1_14,
532 m2_12 * m1_3 + m2_13 * m1_7 + m2_14 * m1_11 + m2_15 * m1_15]
533
534 return self
535
537
538 """Multiplies this matrix by another. Assumes that both matrices have
539 a right column of (0, 0, 0, 1). This is true for matrices composed
540 of rotations, translations and scales. fast_mul is approximately 25%
541 quicker than the *= operator.
542
543 rhs -- A matrix
544
545 """
546
547 m1_0, m1_1, m1_2, m1_3, \
548 m1_4, m1_5, m1_6, m1_7, \
549 m1_8, m1_9, m1_10, m1_11, \
550 m1_12, m1_13, m1_14, m1_15 = self._m
551
552 m2_0, m2_1, m2_2, m2_3, \
553 m2_4, m2_5, m2_6, m2_7, \
554 m2_8, m2_9, m2_10, m2_11, \
555 m2_12, m2_13, m2_14, m2_15 = rhs._m
556
557
558 self._m = [ m2_0 * m1_0 + m2_1 * m1_4 + m2_2 * m1_8,
559 m2_0 * m1_1 + m2_1 * m1_5 + m2_2 * m1_9,
560 m2_0 * m1_2 + m2_1 * m1_6 + m2_2 * m1_10,
561 0.0,
562
563 m2_4 * m1_0 + m2_5 * m1_4 + m2_6 * m1_8,
564 m2_4 * m1_1 + m2_5 * m1_5 + m2_6 * m1_9,
565 m2_4 * m1_2 + m2_5 * m1_6 + m2_6 * m1_10,
566 0.0,
567
568 m2_8 * m1_0 + m2_9 * m1_4 + m2_10 * m1_8,
569 m2_8 * m1_1 + m2_9 * m1_5 + m2_10 * m1_9,
570 m2_8 * m1_2 + m2_9 * m1_6 + m2_10 * m1_10,
571 0.0,
572
573 m2_12 * m1_0 + m2_13 * m1_4 + m2_14 * m1_8 + m1_12,
574 m2_12 * m1_1 + m2_13 * m1_5 + m2_14 * m1_9 + m1_13,
575 m2_12 * m1_2 + m2_13 * m1_6 + m2_14 * m1_10 + m1_14,
576 1.0 ]
577
578 return self
579
581 """Returns a copy of this matrix."""
582 return self.clone(self)
583 __copy__ = copy
584
585
587 """Returns an iterator for the components in the Matrix44. ie
588 returns all 16 values."""
589
590 return iter(self._m[:])
591
592
594 """Returns an iterator for the components in the Matrix44 in
595 transposed order."""
596
597 m00, m01, m02, m03, \
598 m10, m11, m12, m13, \
599 m20, m21, m22, m23, \
600 m30, m31, m32, m33 = self._m
601
602 return iter( ( m00, m10, m20, m30,
603 m01, m11, m21, m31,
604 m02, m12, m22, m32,
605 m03, m13, m23, m33 ) )
606
607
609 """Returns an iterator for the rows in the Matrix44 (yields 4 tuples
610 of 4 values)."""
611
612 m = self._m
613 return iter(( tuple(m[0:4]),
614 tuple(m[4:8]),
615 tuple(m[8:12]),
616 tuple(m[12:16]) ))
617
618
619
621 """Returns an iterator for the columns in the Matrix44 (yields 4
622 tuples of 4 values)."""
623
624 col = self.get_column
625 return iter((col(0), col(1), col(2), col(3)))
626
627
628
630 """Returns a Vector3 for a given row.
631
632 row_no -- The row index
633
634 """
635
636 try:
637 r = row_no*4
638 x, y, z = self._m[r:r+3]
639 return Vector3.from_floats(x, y, z)
640 except IndexError:
641 raise IndexError( "Row and Column should be 0, 1, 2 or 3" )
642
643
645 """Returns a column as a tuple of 4 values.
646
647 col_no -- The column index
648
649 """
650
651 try:
652 m = self._m
653 return ( m[col_no],
654 m[col_no+4],
655 m[col_no+8],
656 m[col_no+12] )
657 except IndexError:
658 raise IndexError( "Column should be 0, 1, 2 or 3" )
659
660
662 """Sets the values in a row.
663
664 row_no -- The index of the row
665 row -- An container containing the new values
666
667 """
668
669 try:
670 self._setters[row_no](self, row)
671 except IndexError:
672 raise IndexError( "Row should be 0, 1, 2 or 3" )
673
674
676 """Sets the values in a column.
677
678 col_no -- The index of the column
679 col -- An sequence of 4 values
680
681 """
682
683 try:
684 col_iter = iter(col)
685 m = self._m
686 a, b, c, d = col
687 m[col_no] = float(a)
688 m[col_no+4] = float(b)
689 m[col_no+8] = float(c)
690 m[col_no+12] = float(d)
691
692 except IndexError:
693 raise IndexError( "Column should be 0, 1, 2 or 3" )
694
695
708
721
722
735
736
748
749
762
763
782
783
802
803 iter_transform3 = iter_transform
804
805
824
825
827 """Rotates a Vector3 and returns the result.
828 The translation part of the Matrix44 is ignored.
829
830 v -- Vector to rotate
831
832 """
833
834 m = self._m
835 x, y, z = v
836 return Vector3.from_floats( x * m[0] + y * m[4] + z * m[8],
837 x * m[1] + y * m[5] + z * m[9],
838 x * m[2] + y * m[6] + z * m[10] )
839
840
842 """Rotates a Vector3 and returns the result as a tuple
843 The translation part of the Matrix44 is ignored.
844
845 v -- Vector to rotate
846
847 """
848
849 m = self._m
850 x, y, z = v
851 return ( x * m[0] + y * m[4] + z * m[8],
852 x * m[1] + y * m[5] + z * m[9],
853 x * m[2] + y * m[6] + z * m[10] )
854
855
866
867
869 """Makes an identity Matrix44."""
870
871 self._m = [1., 0., 0., 0.,
872 0., 1., 0., 0.,
873 0., 0., 1., 0.,
874 0., 0., 0., 1.]
875 return self
876
877
879 """Makes a copy of another Matrix44."""
880
881 self._m = other._m[:]
882 return self
883
884
885 - def make_scale(self, scale_x, scale_y= None, scale_z= None):
886 """Makes a scale Matrix44.
887
888 If the scale_y and scale_z parameters are not given they default to the same as scale_x.
889
890 """
891 if scale_y is None:
892 scale_y = scale_x
893 if scale_z is None:
894 scale_z = scale_x
895
896 self._m = [float(scale_x), 0., 0., 0.,
897 0., float(scale_y), 0., 0.,
898 0., 0., float(scale_z), 0.,
899 0., 0., 0., 1.]
900 return self
901
902
904 """Makes a translation Matrix44."""
905
906 self._m = [1., 0., 0., 0.,
907 0., 1., 0., 0.,
908 0., 0., 1., 0.,
909 float(x), float(y), float(z), 1.]
910 return self
911
912
914 """Makes a rotation Matrix44 around the x axis."""
915
916 cos_a = cos(angle)
917 sin_a = sin(angle)
918
919 self._m = [1., 0., 0., 0.,
920 0., cos_a, sin_a, 0.,
921 0., -sin_a, cos_a, 0.,
922 0., 0., 0., 1.]
923 return self
924
926 """Makes a rotation Matrix44 around the y axis."""
927
928 cos_a = cos(angle)
929 sin_a = sin(angle)
930
931 self._m = [ cos_a, 0., -sin_a, 0.,
932 0., 1., 0., 0.,
933 sin_a, 0., cos_a, 0.,
934 0., 0., 0., 1.]
935 return self
936
937
939 """Makes a rotation Matrix44 around the z axis."""
940
941 cos_a = cos(angle)
942 sin_a = sin(angle)
943
944 self._m = [ cos_a, sin_a, 0., 0.,
945 -sin_a, cos_a, 0., 0.,
946 0., 0., 1., 0.,
947 0., 0., 0., 1.]
948 return self
949
950
952 """Makes a rotation Matrix44 around an axis.
953
954 axis -- An iterable containing the axis (three values)
955 angle -- The angle to rotate (in radians)
956
957 """
958
959 c = cos(angle)
960 s = sin(angle)
961 omc = 1. - c
962 x, y, z = axis
963
964 self._m = [x*x*omc+c, y*x*omc+z*s, x*z*omc-y*s, 0.,
965 x*y*omc-z*s, y*y*omc+c, y*z*omc+x*s, 0.,
966 x*z*omc+y*s, y*z*omc-x*s, z*z*omc+c, 0.,
967 0., 0., 0., 1.]
968 return self
969
970
972 """Makes a rotation Matrix44 about 3 axis."""
973
974 cx = cos(angle_x)
975 sx = sin(angle_x)
976 cy = cos(angle_y)
977 sy = sin(angle_y)
978 cz = cos(angle_z)
979 sz = sin(angle_z)
980
981 sxsy = sx*sy
982 cxsy = cx*sy
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997 self._m = [ cy*cz, sxsy*cz+cx*sz, -cxsy*cz+sx*sz, 0.,
998 -cy*sz, -sxsy*sz+cx*cz, cxsy*sz+sx*cz, 0.,
999 sy, -sx*cy, cx*cy, 0.,
1000 0., 0., 0., 1.]
1001
1002 return self
1003
1004
1006 """Makes a perspective projection Matrix44.
1007
1008 left -- Coordinate of left of screen
1009 right -- Coordination of right of screen
1010 top -- Coordination of the top of the screen
1011 bottom -- Coordination of the borrom of the screen
1012 near -- Coordination of the near clipping plane
1013 far -- Coordinate of the far clipping plane
1014
1015 """
1016
1017 self._m = [(2.*near)/(right-left), 0., 0., 0.,
1018 0., (2.*near)/(top-bottom), 0., 0.,
1019 (right+left)/(right-left), (top+bottom)/(top-bottom), -((far+near)/(far-near)), -1.,
1020 0., 0., -((2.*far*near)/(far-near)), 0.]
1021 return self
1022
1023
1025 """Creates a Matrix44 that projects points in to 2d space
1026
1027 fov -- The field of view (in radians)
1028 aspect -- The aspect ratio of the screen (width / height)
1029 near -- Coordinate of the near clipping plane
1030 far -- Coordinate of the far clipping plane
1031
1032 """
1033
1034 assert fov < pi, "The field of view should be less than pi radians"\
1035 " (180 degrees)"
1036
1037 range = near*tan(fov/2.);
1038 left = -range*aspect
1039 right = range*aspect
1040 bottom = -range
1041 top = range
1042
1043
1044
1045
1046
1047 self.make_perspective_projection(left, right, bottom, top, near, far)
1048 return self
1049
1050
1052 """Swaps the rows for columns."""
1053
1054 m00, m01, m02, m03, \
1055 m10, m11, m12, m13, \
1056 m20, m21, m22, m23, \
1057 m30, m31, m32, m33 = self._m
1058
1059 self._m = [ m00, m10, m20, m30,
1060 m01, m11, m21, m31,
1061 m02, m12, m22, m32,
1062 m03, m13, m23, m33 ]
1063
1064
1066 """Returns a Matrix44 that is a copy of this, but with rows and
1067 columns swapped."""
1068
1069 m00, m01, m02, m03, \
1070 m10, m11, m12, m13, \
1071 m20, m21, m22, m23, \
1072 m30, m31, m32, m33 = self._m
1073
1074 ret = self.__new__(self.__class__, object)
1075
1076 ret._m = [ m00, m10, m20, m30,
1077 m01, m11, m21, m31,
1078 m02, m12, m22, m32,
1079 m03, m13, m23, m33 ]
1080
1081 return ret
1082
1083
1085 """Returns the inverse of a Matrix44 with only rotation and
1086 translation. This is faster than the general get_inverse method."""
1087
1088 ret = self.copy()
1089 m = ret._m
1090
1091 i0, i1, i2, i3, \
1092 i4, i5, i6, i7, \
1093 i8, i9, i10, i11, \
1094 i12, i13, i14, i15 = self._m
1095
1096 m[1] = i4
1097 m[4] = i1
1098 m[2] = i8
1099 m[8] = i2
1100 m[6] = i9
1101 m[9] = i6
1102
1103 m[12] = ( m[0] * -i12 +
1104 m[4] * -i13 +
1105 m[8] * -i14 )
1106
1107 m[13] = ( m[1] * -i12 +
1108 m[5] * -i13 +
1109 m[9] * -i14 )
1110
1111 m[14] = ( m[2] * -i12 +
1112 m[6] * -i13 +
1113 m[10] * -i14 )
1114
1115 return ret
1116
1117
1119
1120 """Returns the inverse (matrix with the opposite effect) of this
1121 matrix."""
1122
1123 ret = self.__new__(self.__class__, object)
1124 i = self._m
1125
1126 i0, i1, i2, i3, \
1127 i4, i5, i6, i7, \
1128 i8, i9, i10, i11, \
1129 i12, i13, i14, i15 = i
1130
1131 negpos=[0., 0.]
1132 temp = i0 * i5 * i10
1133 negpos[temp > 0.] += temp
1134
1135 temp = i1 * i6 * i8
1136 negpos[temp > 0.] += temp
1137
1138 temp = i2 * i4 * i9
1139 negpos[temp > 0.] += temp
1140
1141 temp = -i2 * i5 * i8
1142 negpos[temp > 0.] += temp
1143
1144 temp = -i1 * i4 * i10
1145 negpos[temp > 0.] += temp
1146
1147 temp = -i0 * i6 * i9
1148 negpos[temp > 0.] += temp
1149
1150 det_1 = negpos[0]+negpos[1]
1151
1152 if (det_1 == 0.) or (abs(det_1 / (negpos[1] - negpos[0])) < \
1153 (2. * 0.00000000000000001) ):
1154 raise Matrix44Error("notivertable", "This Matrix44 can not be inverted")
1155
1156 det_1 = 1. / det_1
1157
1158 ret._m = [ (i5*i10 - i6*i9)*det_1,
1159 -(i1*i10 - i2*i9)*det_1,
1160 (i1*i6 - i2*i5 )*det_1,
1161 0.0,
1162 -(i4*i10 - i6*i8)*det_1,
1163 (i0*i10 - i2*i8)*det_1,
1164 -(i0*i6 - i2*i4)*det_1,
1165 0.0,
1166 (i4*i9 - i5*i8 )*det_1,
1167 -(i0*i9 - i1*i8)*det_1,
1168 (i0*i5 - i1*i4)*det_1,
1169 0.0,
1170 0.0, 0.0, 0.0, 1.0 ]
1171
1172 m = ret._m
1173 m[12] = - ( i12 * m[0] + i13 * m[4] + i14 * m[8] )
1174 m[13] = - ( i12 * m[1] + i13 * m[5] + i14 * m[9] )
1175 m[14] = - ( i12 * m[2] + i13 * m[6] + i14 * m[10] )
1176
1177 return ret
1178
1179
1181
1182 """Inverts this matrix."""
1183
1184 self._m[:] = self.get_inverse()._m
1185
1186
1187 - def move(self, forward=None, right=None, up=None):
1188
1189 """Changes the translation according to a direction vector.
1190 To move in opposite directions (i.e back, left and down), first
1191 negate the vector.
1192
1193 forward -- Units to move in the 'forward' direction
1194 right -- Units to move in the 'right' direction
1195 up -- Units to move in the 'up' direction
1196
1197 """
1198
1199 if forward is not None:
1200 self.translate = Vector3(self.translate) + \
1201 Vector3(self.forward) * forward
1202
1203 if right is not None:
1204 self.translate = Vector3(self.translate) + \
1205 Vector3(self.right) * right
1206
1207 if up is not None:
1208 self.translate = Vector3(self.translate) + \
1209 Vector3(self.up) * up
1210
1211
1212
1214
1215 m = Matrix44.xyz_rotation(radians(45), radians(20), radians(0))
1216
1217
1218 print m.right
1219 print m.right.as_vec3()
1220
1221 n = m.copy()
1222
1223 r = Matrix44.z_rotation(radians(32))
1224 m *= r
1225 print m
1226 n.fast_mul( r )
1227
1228 print n
1229
1230 print "--Transpose"
1231
1232 print m.get_transpose()
1233
1234 print "--"
1235
1236 print m.get_row(2)
1237
1238 m.transpose()
1239 print m
1240
1241 print
1242
1243
1244
1245 m.translate = (m.translate[:3]) + Vector3(10, 20, 30)
1246
1247 print m
1248
1249 print
1250
1251 v = (1., 2., 3.)
1252 print v
1253 vt = m.transform(v)
1254 print vt
1255
1256 vit = m.get_inverse().transform(vt)
1257
1258 print vit
1259
1260
1261 print m.inverse_transform(vt)
1262 m[1,2] = 3.
1263
1264 print
1265
1266 print m.x_axis
1267 print m.translate
1268 m.translate = (1, 2, 3)
1269
1270 print m
1271
1272 identity = Matrix44()
1273
1274 print identity
1275
1276 identity[3, 1] = 456
1277
1278
1279 print identity
1280 print eval(repr(identity))
1281
1282 print m
1283
1284 print m.translate + Vector3(1, 2, 3)
1285
1286 print m
1287
1288 m.translate = (0, 0, 0)
1289
1290 if __name__ == "__main__":
1291
1292 test()
1293