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