~jtaylor/ubuntu/oneiric/soya/fix-780305

« back to all changes in this revision

Viewing changes to math3d.py

  • Committer: Bazaar Package Importer
  • Author(s): Marc Dequènes (Duck)
  • Date: 2005-01-30 09:55:06 UTC
  • mfrom: (1.2.1 upstream) (2.1.1 hoary)
  • Revision ID: james.westby@ubuntu.com-20050130095506-f21p6v6cgaobhn5j
Tags: 0.9.2-1
New upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
# along with this program; if not, write to the Free Software
16
16
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17
17
 
18
 
"""soya.math3d
19
 
 
20
 
This module provides the Point and Vector classes that are used for 3D math
21
 
computation, such as coordinates system conversion.
22
 
 
23
 
In Soya 3D, a position is defined by 3 coordinates
24
 
(x, y, z) AND the coordinates system in which the coordinates are defined
25
 
(sometime called the "parent").
26
 
 
27
 
Points and Vectors are used for math computation; my own experience in 3D
28
 
has convinced me that ANY complicated 3D computation can be heavily
29
 
simplified by the use of coordinates system conversions. As Soya 3D
30
 
associates the coordinates system along with the coordinates values, it
31
 
performs coordinates system conversion automagically !"""
32
 
 
33
 
import math
34
 
import soya
35
 
import _soya
36
 
import copy_reg
37
 
 
38
 
 
39
 
class Parentable:
40
 
  def __deepcopy__(self, memo):
41
 
    # Do not clone the parent (except if already cloned before, in the memo) !
42
 
    import copy
43
 
    
44
 
    red = self.__reduce__()
45
 
    clone = red[1][0]()
46
 
    memo[id(self)] = clone
47
 
    state = red[2]
48
 
    
49
 
    if self.parent and (not id(self.parent) in memo.keys()):
50
 
      state = (None, state[1], state[2], state[3])
51
 
      
52
 
    s2 = copy.deepcopy(state, memo)
53
 
    clone.__setstate__(s2)
54
 
    return clone
55
 
 
56
 
 
57
 
class Point(Parentable, _soya._Point):
58
 
  pass
59
 
 
60
 
class Vector(Parentable, _soya._Vector):
61
 
  pass
62
 
 
63
 
__all__ = ["Point", "Vector"]
64
 
 
65
 
#Point  = _soya.Point
66
 
#Vector = _soya.Vector
67
 
 
68
 
#def soya_generic_reduce (obj):
69
 
#  return (soya._soya_reconstructor, (obj.__class__, ), obj.__getstate__())
70
 
 
71
 
#copy_reg.constructor(Point)
72
 
#copy_reg.constructor(Vector)
73
 
#copy_reg.pickle(Point,  soya_generic_reduce, soya._soya_reconstructor)
74
 
#copy_reg.pickle(Vector, soya_generic_reduce, soya._soya_reconstructor)
75
 
 
76
 
 
77
 
 
78
 
## class Point(_soya.Point):
79
 
## #class Point(object):
80
 
##   "A Point is a 3D position."
81
 
  
82
 
##   def __init__(self, parent = None, x = 0.0, y = 0.0, z = 0.0):
83
 
##     """Point(parent = None, x = 0.0, y = 0.0, z = 0.0)
84
 
 
85
 
## Creates a new Point, with coordinates X, Y and Z, defined in the coordinates
86
 
## system PARENT.
87
 
## """
88
 
 
89
 
##     _soya.Point.__init__(self, parent, x, y, z)
90
 
    
91
 
##     # Very common error
92
 
##     #assert parent.__class__ is not float, "Parent must be a coordinate system !!!"
93
 
##     if parent.__class__ is float: raise TypeError, "Parent must be a coordinate system !!!"
94
 
    
95
 
##     self.parent = parent
96
 
    
97
 
##     self.x = x
98
 
##     self.y = y
99
 
##     self.z = z
100
 
    
101
 
##   def get_root(self):
102
 
##     """Point.get_root() -> World
103
 
 
104
 
## Gets the root parent of a Point. The root parent is the root World of the
105
 
## hierarchy (often called the "scene" object)."""
106
 
##     if self.parent: return self.parent.get_root()
107
 
    
108
 
##   def set_xyz(self, x, y, z):
109
 
##     """Point.set_xyz(x, y, z)
110
 
 
111
 
## Sets the coordinates of a point to X, Y and Z."""
112
 
##     self.x = x
113
 
##     self.y = y
114
 
##     self.z = z
115
 
    
116
 
##   def move(self, position):
117
 
##     """Point.move(position)
118
 
 
119
 
## Moves a Point to POSITION (a Point or another 3D object, such as a World,
120
 
## a volume,...).
121
 
## Coordinates system conversion is performed if needed (=if the Point and
122
 
## POSITION are not defined in the same coordinates system)."""
123
 
##     if (not position.parent) or (not self.parent) or (self.parent is position.parent):
124
 
##       self.x = position.x
125
 
##       self.y = position.y
126
 
##       self.z = position.z
127
 
##     else:
128
 
##       self.x, self.y, self.z = self.parent.transform_point(position.x, position.y, position.z, position.parent)
129
 
      
130
 
##   def convert_to(self, parent):
131
 
##     """Point.convert_to(parent)
132
 
 
133
 
## Converts a Point to the coordinates system PARENT in place. The x, y and z
134
 
## coordinates are modified, and the Point's parent is set to PARENT."""
135
 
##     if parent:
136
 
##       self.x, self.y, self.z = parent.transform_point(self.x, self.y, self.z, self.parent)
137
 
##     self.parent = parent
138
 
##   __imod__ = convert_to
139
 
  
140
 
##   def copy(self):
141
 
##     """Point.copy() -> Point
142
 
 
143
 
## Returns a copy of a Point."""
144
 
##     return Point(self.parent, self.x, self.y, self.z)
145
 
##   position = copy
146
 
  
147
 
##   def clone(self, other):
148
 
##     """Point.clone(other)
149
 
 
150
 
## Changes IN PLACE this Point so as it is a clone of OTHER."""
151
 
##     self.parent = other.parent
152
 
##     self.x= other.x
153
 
##     self.y= other.y
154
 
##     self.z= other.z
155
 
    
156
 
##   def __mod__(self, coordsyst):
157
 
##     """Point % coordsyst -> Point
158
 
 
159
 
## Converts a Point to the coordinates system COORDSYST and returns the result.
160
 
## The returned value may be the same Point if its coordinates system is
161
 
## already COORDSYST, so you should be carreful if you modify it."""
162
 
##     if (not self.parent) or (not coordsyst) or (self.parent is coordsyst): return self
163
 
##     p = Point(self.parent, self.x, self.y, self.z)
164
 
##     p.convert_to(coordsyst)
165
 
##     return p
166
 
  
167
 
##   def __add__(self, vector):
168
 
##     """Point + Vector -> Point
169
 
 
170
 
## Translates a Point and returns the result (a new Point).
171
 
## Coordinates system conversion is performed if needed (=if the Point and
172
 
## VECTOR are not defined in the same coordinates system)."""
173
 
##     if (not vector.parent) or (not self.parent) or (self.parent is vector.parent):
174
 
##       return Point(self.parent, self.x + vector.x, self.y + vector.y, self.z + vector.z)
175
 
##     else:
176
 
##       x, y, z = self.parent.transform_vector(vector.x, vector.y, vector.z, vector.parent)
177
 
##       return Point(self.parent, self.x + x, self.y + y, self.z + z)
178
 
  
179
 
##   def __sub__(self, vector):
180
 
##     """Point - Vector -> Point
181
 
 
182
 
## Translates a Point and returns the result (a new Point).
183
 
## Coordinates system conversion is performed if needed (=if the Point and
184
 
## VECTOR are not defined in the same coordinates system)."""
185
 
##     if (not vector.parent) or (not self.parent) or (self.parent is vector.parent):
186
 
##       return Point(self.parent, self.x - vector.x, self.y - vector.y, self.z - vector.z)
187
 
##     else:
188
 
##       x, y, z = self.parent.transform_vector(vector.x, vector.y, vector.z, vector.parent)
189
 
##       return Point(self.parent, self.x - x, self.y - y, self.z - z)
190
 
  
191
 
##   def add_xyz(self, x, y, z):
192
 
##     """Point.add_xyz(x, y, z)
193
 
 
194
 
## Translates the coordinates of a point by X, Y and Z."""
195
 
##     self.x += x
196
 
##     self.y += y
197
 
##     self.z += z
198
 
    
199
 
##   def add_vector(self, vector):
200
 
##     """Point.add_vector(vector)
201
 
 
202
 
## Translates a Point IN PLACE.
203
 
## Coordinates system conversion is performed if needed (=if the Point and
204
 
## VECTOR are not defined in the same coordinates system).
205
 
 
206
 
## For Vector, add_vector means vectorial addition (translating a vector does
207
 
## nothing !)."""
208
 
##     if (not vector.parent) or (not self.parent) or (self.parent is vector.parent):
209
 
##       self.x += vector.x
210
 
##       self.y += vector.y
211
 
##       self.z += vector.z
212
 
##     else:
213
 
##       x, y, z = self.parent.transform_vector(vector.x, vector.y, vector.z, vector.parent)
214
 
##       self.x += x
215
 
##       self.y += y
216
 
##       self.z += z
217
 
      
218
 
##     return self
219
 
##   __iadd__ = add_vector
220
 
  
221
 
##   def add_mul_vector(self, k, vector):
222
 
##     """Point.add_mul_vector(k, vector)
223
 
 
224
 
## Translates a Point IN PLACE, by K * VECTOR.
225
 
## Coordinates system conversion is performed if needed (=if the Point and
226
 
## VECTOR are not defined in the same coordinates system).
227
 
 
228
 
## For Vector, add_vector means vectorial addition (translating a vector does
229
 
## nothing !)."""
230
 
##     if (not vector.parent) or (not self.parent) or (self.parent is vector.parent):
231
 
##       self.x += k * vector.x
232
 
##       self.y += k * vector.y
233
 
##       self.z += k * vector.z
234
 
##     else:
235
 
##       x, y, z = self.parent.transform_vector(vector.x, vector.y, vector.z, vector.parent)
236
 
##       self.x += k * x
237
 
##       self.y += k * y
238
 
##       self.z += k * z
239
 
##     return self
240
 
  
241
 
##   def distance_to(self, other):
242
 
##     """Point.distance_to(other) -> float
243
 
 
244
 
## Gets the distance between a Point and anOTHER."""
245
 
##     if (not other.parent) or (not self.parent) or (self.parent is other.parent):
246
 
##       return math.sqrt((self.x - other.x) ** 2 + (self.y - other.y) ** 2 + (self.z - other.z) ** 2)
247
 
##     else:
248
 
##       x, y, z = self.parent.transform_point(other.x, other.y, other.z, other.parent)
249
 
##       return math.sqrt((self.x - x) ** 2 + (self.y - y) ** 2 + (self.z - z) ** 2)
250
 
    
251
 
##   def vector_to(self, other):
252
 
##     """Point.vector_to(other) -> Vector
253
 
 
254
 
## Gets the vector that starts at a Point and ends at OTHER."""
255
 
##     if (not other.parent) or (not self.parent) or (self.parent is other.parent):
256
 
##       return Vector(self.parent, other.x - self.x, other.y - self.y, other.z - self.z)
257
 
##     else:
258
 
##       x, y, z = self.parent.transform_point(other.x, other.y, other.z, other.parent)
259
 
##       return Vector(self.parent, x - self.x, y - self.y, z - self.z)
260
 
##   __rshift__ = vector_to
261
 
  
262
 
##   def __eq__(self, other):
263
 
##     return hasattr(other, "x") and hasattr(other, "y") and hasattr(other, "z") and hasattr(other, "parent") and (self.parent is other.parent) and (self.x == other.x) and (self.y == other.y) and (self.z == other.z)
264
 
  
265
 
##   def __ne__(self, other):
266
 
##     return hasattr(other, "x") and hasattr(other, "y") and hasattr(other, "z") and hasattr(other, "parent") and (not (self.parent is other.parent) and (self.x == other.x) and (self.y == other.y) and (self.z == other.z))
267
 
  
268
 
##   def __repr__(self): return "<Point %s, %s, %s in %s>" % (self.x, self.y, self.z, self.parent)
269
 
  
270
 
## #   def __deepcopy__(self, memo):
271
 
## #     # Don't copy the parent !
272
 
## #     import copy
273
 
    
274
 
## #     red = self.__reduce__()
275
 
    
276
 
## #     clone = _Empty()
277
 
## #     clone.__class__ = red[1][0]
278
 
## #     memo[id(self)] = clone
279
 
    
280
 
## #     state = red[2]
281
 
## #     if state is self.__dict__: state = state.copy()
282
 
## #     copy._keep_alive(state, memo)
283
 
      
284
 
## #     if not id(self.parent) in memo.keys():
285
 
## #       del state["parent"]
286
 
## #       state = copy.deepcopy(state, memo)
287
 
## #       state["parent"] = self.parent
288
 
## #     else:
289
 
## #       state = copy.deepcopy(state, memo)
290
 
## #     copy._keep_alive(state, memo)
291
 
    
292
 
## #     if hasattr(clone, "__setstate__"): clone.__setstate__(state)
293
 
## #     else:                              clone.__dict__ = state
294
 
    
295
 
## #     return clone
296
 
  
297
 
  
298
 
##   def __deepcopy__(self, memo):
299
 
##     # Do not clone the parent (except if already cloned before, in the memo) !
300
 
##     import copy
301
 
    
302
 
##     red = self.__reduce__()
303
 
    
304
 
##     clone = red[1][0]()
305
 
##     memo[id(self)] = clone
306
 
    
307
 
##     state = red[2]
308
 
  
309
 
##     if not id(self.parent) in memo.keys():
310
 
##       state = copy.copy(state)
311
 
##       state["parent"] = None
312
 
 
313
 
##     s2 = copy.deepcopy(state, memo)
314
 
    
315
 
##     if hasattr(clone, "__setstate__"): clone.__setstate__(s2)
316
 
##     else:                              clone.__dict__ = s2
317
 
    
318
 
##     return clone
319
 
 
320
 
  
321
 
 
322
 
 
323
 
## class Vector(_soya.Vector):
324
 
## #class Vector(Point):
325
 
##   """A Vector is a 3D vector (and not a kind of list or sequence ;-). Vectors are
326
 
## usefull for 3D math computation. 
327
 
 
328
 
## Most of the math operator, such as +, -, *, /, abs,... work on Vectors and do
329
 
## what they are intended to do ;-)
330
 
 
331
 
## Vector inherits from Point for practical reasons, since both have x, y, z
332
 
## coordinates and a parent."""
333
 
  
334
 
##   def __init__(_self, _parent = None, _x = 0.0, _y = 0.0, _z = 0.0):
335
 
##     _soya.Vector.__init__(_self, _parent, _x, _y, _z)
336
 
 
337
 
##   def move(self, position):
338
 
##     """Vector.move(position)
339
 
 
340
 
## Moves a Vector to POSITION (a Vector).
341
 
## Coordinates system conversion is performed if needed (=if the Vector and
342
 
## POSITION are not defined in the same coordinates system)."""
343
 
##     if (not position.parent) or (not self.parent) or (self.parent is position.parent):
344
 
##       self.x = position.x
345
 
##       self.y = position.y
346
 
##       self.z = position.z
347
 
##     else:
348
 
##       self.x, self.y, self.z = self.parent.transform_vector(position.x, position.y, position.z, position.parent)
349
 
      
350
 
##   def convert_to(self, parent):
351
 
##     """Vector.convert_to(parent)
352
 
 
353
 
## Converts a Vector to the coordinates system PARENT in place. The x, y and z
354
 
## coordinates are modified, and the Vector's parent is set to PARENT."""
355
 
##     if parent: self.x, self.y, self.z = parent.transform_vector(self.x, self.y, self.z, self.parent)
356
 
##     self.parent = parent
357
 
##   __imod__ = convert_to
358
 
  
359
 
##   def copy(self):
360
 
##     """Vector.copy() -> Vector
361
 
 
362
 
## Returns a copy of a Vector."""
363
 
##     return Vector(self.parent, self.x, self.y, self.z)
364
 
##   position = copy
365
 
  
366
 
##   def cross_product(self, vector):
367
 
##     """Vector.cross_product(VECTOR) -> Vector
368
 
 
369
 
## Returns the cross product of a Vector with VECTOR."""
370
 
##     return _soya.cross_vector(self, vector)
371
 
  
372
 
##   def dot_product(self, vector):
373
 
##     """Vector.dot_product(VECTOR) -> float
374
 
 
375
 
## Returns the dot product of a Vector with VECTOR."""
376
 
##     if (not vector.parent) or (not self.parent) or (self.parent is vector.parent):
377
 
##       return self.x * vector.x + self.y * vector.y + self.z * vector.z
378
 
##     else:
379
 
##       x, y, z = self.parent.transform_vector(vector.x, vector.y, vector.z, vector.parent)
380
 
##       return self.x * x + self.y * y + self.z * z
381
 
  
382
 
##   def length(self):
383
 
##     """Vector.length() -> float
384
 
 
385
 
## Gets the length of a Vector."""
386
 
##     return math.sqrt(self.x ** 2 + self.y ** 2 + self.z ** 2)
387
 
    
388
 
##   def set_length(self, new_length):
389
 
##     """Vector.set_length(new_length)
390
 
 
391
 
## Sets the length of a Vector to NEW_LENGTH. The Vector's coordinates are
392
 
## multiplicated as needed."""
393
 
##     f = new_length / self.length()
394
 
##     self.x *= f
395
 
##     self.y *= f
396
 
##     self.z *= f
397
 
    
398
 
##   def __mod__(self, coordsyst):
399
 
##     """Vector % coordsyst -> Vector
400
 
 
401
 
## Converts a Vector to the coordinates system COORDSYST and returns the result.
402
 
## The returned value may be the same Vector if its coordinates system is
403
 
## already COORDSYST, so you should be carreful if you modify it."""
404
 
 
405
 
##     if (not self.parent) or (not coordsyst) or (self.parent is coordsyst): return self
406
 
##     v = Vector(self.parent, self.x, self.y, self.z)
407
 
##     v.convert_to(coordsyst)
408
 
##     return v
409
 
  
410
 
##   def __mul__(self, number): return Vector(self.parent, self.x * number, self.y * number, self.z * number)
411
 
##   def __div__(self, number): return Vector(self.parent, self.x / number, self.y / number, self.z / number)
412
 
##   __truediv__ = __div__
413
 
  
414
 
##   def __imul__(self, number):
415
 
##     self.x *= number
416
 
##     self.y *= number
417
 
##     self.z *= number
418
 
##     return self
419
 
  
420
 
##   def __idiv__(self, number):
421
 
##     self.x /= number
422
 
##     self.y /= number
423
 
##     self.z /= number
424
 
##     return self
425
 
    
426
 
##   def __add__(self, vector):
427
 
##     if (not vector.parent) or (not self.parent) or (self.parent is vector.parent):
428
 
##       return Vector(self.parent, self.x + vector.x, self.y + vector.y, self.z + vector.z)
429
 
##     else:
430
 
##       x, y, z = self.parent.transform_vector(vector.x, vector.y, vector.z, vector.parent)
431
 
##       return Vector(self.parent, self.x + x, self.y + y, self.z + z)
432
 
  
433
 
##   def __sub__(self, vector):
434
 
##     if (not vector.parent) or (not self.parent) or (self.parent is vector.parent):
435
 
##       return Vector(self.parent, self.x - vector.x, self.y - vector.y, self.z - vector.z)
436
 
##     else:
437
 
##       x, y, z = self.parent.transform_vector(vector.x, vector.y, vector.z, vector.parent)
438
 
##       return Vector(self.parent, self.x - x, self.y - y, self.z - z)
439
 
  
440
 
##   def __neg__(self): return Vector(self.parent, -self.x, -self.y, -self.z)
441
 
  
442
 
##   def __abs__(self): return Vector(self.parent, abs(self.x), abs(self.y), abs(self.z))
443
 
  
444
 
##   def normalize(self):
445
 
##     """Vector.normalize()
446
 
 
447
 
## Normalizes a Vector IN PLACE."""
448
 
##     length = self.length()
449
 
##     self.x /= length
450
 
##     self.y /= length
451
 
##     self.z /= length
452
 
    
453
 
##   def __repr__(self): return "<Vector %s, %s, %s in %s>" % (self.x, self.y, self.z, self.parent)
454
 
  
455
 
##   def set_start_end(self, start, end):
456
 
##     """Vector.set_start_end(start, end)
457
 
 
458
 
## Sets this vector IN PLACE so as it correspond to the vector start->end."""
459
 
##     self.parent = start.parent
460
 
    
461
 
##     if (not start.parent) or (not end.parent) or (start.parent is end.parent):
462
 
##       self.x = end.x - start.x
463
 
##       self.y = end.y - start.y
464
 
##       self.z = end.z - start.z
465
 
##     else:
466
 
##       x, y, z = self.parent.transform_point(end.x, end.y, end.z, end.parent)
467
 
##       self.x = x - start.x
468
 
##       self.y = y - start.y
469
 
##       self.z = z - start.z
470
 
 
471
 
##   def angle_to(self, vector):
472
 
##     """Vector.angle_to(VECTOR) -> angle in degree
473
 
 
474
 
## Computes the angle between this Vector and VECTOR."""
475
 
##     vector = vector % self.parent
476
 
##     s = self.length() * vector.length()
477
 
##     f = self.dot_product(vector) / s
478
 
##     if f >=  1.0: return   0.0
479
 
##     if f <= -1.0: return 180.0
480
 
##     return (math.atan(-f / math.sqrt(1.0 - f * f)) + math.pi / 2.0) * 180.0 / math.pi
481
 
 
482
 
  
483
 
_soya.new_point  = Point
484
 
_soya.new_vector = Vector
 
18
import warnings
 
19
warnings.warn("The content of this module is now in the soya module.", DeprecationWarning)
 
20
 
 
21
from soya import Point, Vector
485
22