Package gameobjects :: Module matrix44
[hide private]
[frames] | no frames]

Source Code for Module gameobjects.matrix44

   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  #import psyco 
   8  #psyco.full() 
   9   
10 -class Matrix44Error(Exception):
11 12 """Matrix44 Exception class""" 13
14 - def __init__(self, code, description):
15 Exception.__init__(self) 16 self.code = code 17 self.description = description
18
19 - def __str__(self):
20 return "%s (%s)" % (self.description, self.code)
21 22
23 -class Row(tuple):
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
32 - def __add__(self, rhs):
33 try: 34 return rhs.__radd__(self[:rhs._gameobjects_vector]) 35 except AttributeError: 36 raise TypeError(self._type_error)
37
38 - def __sub__(self, rhs):
39 try: 40 return rhs.__sub__(self[:rhs._gameobjects_vector]) 41 except AttributeError: 42 raise TypeError(self._type_error)
43
44 - def __mul__(self, rhs):
45 try: 46 return rhs.__mul__(self[:rhs._gameobjects_vector]) 47 except AttributeError: 48 raise TypeError(self._type_error)
49
50 - def __div__(self, rhs):
51 try: 52 return rhs.__div__(self[:rhs._gameobjects_vector]) 53 except AttributeError: 54 raise TypeError(self._type_error)
55 56
57 - def as_vec3(self):
58 """Shorthand for converting to a vector3.""" 59 return Vector3._from_float_sequence(self)
60 61
62 -class Matrix44(object):
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
71 - def __init__(self, *args):
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
103 - def _get_row_0(self):
104 return Row(self._m[0:4])
105
106 - def _get_row_1(self):
107 return Row(self._m[4:8])
108
109 - def _get_row_2(self):
110 return Row(self._m[8:12])
111
112 - def _get_row_3(self):
113 return Row(self._m[12:16])
114
115 - def _set_row_0(self, values):
116 values = tuple(values)[:4] 117 self._m[0:len(values)] = map(float, values)
118
119 - def _set_row_1(self, values):
120 values = tuple(values)[:4] 121 self._m[4:4+len(values)] = map(float, values)
122
123 - def _set_row_2(self, values):
124 values = tuple(values)[:4] 125 self._m[8:8+len(values)] = map(float, values)
126
127 - def _set_row_3(self, values):
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
148 - def to_opengl(self):
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
182 - def get_row(self, row_no):
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
195 - def from_iter(cls, iterable):
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
215 - def blank(cls):
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
228 - def identity(cls):
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
249 - def translation(cls, x, y, z):
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
263 - def x_rotation(cls, angle):
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
275 - def y_rotation(cls, angle):
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
287 - def z_rotation(cls, angle):
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
299 - def rotation_about_axis(cls, axis, angle):
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
312 - def xyz_rotation(cls, angle_x, angle_y, angle_z):
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
326 - def perspective_projection(cls, left, right, top, bottom, near, far):
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
348 - def perspective_projection_fov(cls, fov, aspect, near, far):
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
362 - def __str__(self):
363 """'Pretty' formatting of the Matrix44.""" 364 365 # Pretty printing generates a lot of ugly code - oh the irony! 366 # Changed in release 0.0.3 so that the decimal point is always 367 # line up on the columns 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
396 - def __repr__(self):
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
405 - def __hash__(self):
406 407 """Allows matrices to be used as keys in a dictionary.""" 408 409 return hash(tuple(self._m))
410 411
412 - def __setitem__(self, coord, value):
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
429 - def __getitem__(self, coord):
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