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
20
This module provides the Point and Vector classes that are used for 3D math
21
computation, such as coordinates system conversion.
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").
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 !"""
40
def __deepcopy__(self, memo):
41
# Do not clone the parent (except if already cloned before, in the memo) !
44
red = self.__reduce__()
46
memo[id(self)] = clone
49
if self.parent and (not id(self.parent) in memo.keys()):
50
state = (None, state[1], state[2], state[3])
52
s2 = copy.deepcopy(state, memo)
53
clone.__setstate__(s2)
57
class Point(Parentable, _soya._Point):
60
class Vector(Parentable, _soya._Vector):
63
__all__ = ["Point", "Vector"]
66
#Vector = _soya.Vector
68
#def soya_generic_reduce (obj):
69
# return (soya._soya_reconstructor, (obj.__class__, ), obj.__getstate__())
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)
78
## class Point(_soya.Point):
79
## #class Point(object):
80
## "A Point is a 3D position."
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)
85
## Creates a new Point, with coordinates X, Y and Z, defined in the coordinates
89
## _soya.Point.__init__(self, parent, x, y, z)
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 !!!"
95
## self.parent = parent
101
## def get_root(self):
102
## """Point.get_root() -> World
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()
108
## def set_xyz(self, x, y, z):
109
## """Point.set_xyz(x, y, z)
111
## Sets the coordinates of a point to X, Y and Z."""
116
## def move(self, position):
117
## """Point.move(position)
119
## Moves a Point to POSITION (a Point or another 3D object, such as a World,
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
128
## self.x, self.y, self.z = self.parent.transform_point(position.x, position.y, position.z, position.parent)
130
## def convert_to(self, parent):
131
## """Point.convert_to(parent)
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."""
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
141
## """Point.copy() -> Point
143
## Returns a copy of a Point."""
144
## return Point(self.parent, self.x, self.y, self.z)
147
## def clone(self, other):
148
## """Point.clone(other)
150
## Changes IN PLACE this Point so as it is a clone of OTHER."""
151
## self.parent = other.parent
156
## def __mod__(self, coordsyst):
157
## """Point % coordsyst -> Point
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)
167
## def __add__(self, vector):
168
## """Point + Vector -> Point
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)
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)
179
## def __sub__(self, vector):
180
## """Point - Vector -> Point
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)
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)
191
## def add_xyz(self, x, y, z):
192
## """Point.add_xyz(x, y, z)
194
## Translates the coordinates of a point by X, Y and Z."""
199
## def add_vector(self, vector):
200
## """Point.add_vector(vector)
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).
206
## For Vector, add_vector means vectorial addition (translating a vector does
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
213
## x, y, z = self.parent.transform_vector(vector.x, vector.y, vector.z, vector.parent)
219
## __iadd__ = add_vector
221
## def add_mul_vector(self, k, vector):
222
## """Point.add_mul_vector(k, vector)
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).
228
## For Vector, add_vector means vectorial addition (translating a vector does
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
235
## x, y, z = self.parent.transform_vector(vector.x, vector.y, vector.z, vector.parent)
241
## def distance_to(self, other):
242
## """Point.distance_to(other) -> float
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)
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)
251
## def vector_to(self, other):
252
## """Point.vector_to(other) -> Vector
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)
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
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)
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))
268
## def __repr__(self): return "<Point %s, %s, %s in %s>" % (self.x, self.y, self.z, self.parent)
270
## # def __deepcopy__(self, memo):
271
## # # Don't copy the parent !
274
## # red = self.__reduce__()
276
## # clone = _Empty()
277
## # clone.__class__ = red[1][0]
278
## # memo[id(self)] = clone
281
## # if state is self.__dict__: state = state.copy()
282
## # copy._keep_alive(state, memo)
284
## # if not id(self.parent) in memo.keys():
285
## # del state["parent"]
286
## # state = copy.deepcopy(state, memo)
287
## # state["parent"] = self.parent
289
## # state = copy.deepcopy(state, memo)
290
## # copy._keep_alive(state, memo)
292
## # if hasattr(clone, "__setstate__"): clone.__setstate__(state)
293
## # else: clone.__dict__ = state
298
## def __deepcopy__(self, memo):
299
## # Do not clone the parent (except if already cloned before, in the memo) !
302
## red = self.__reduce__()
304
## clone = red[1][0]()
305
## memo[id(self)] = clone
309
## if not id(self.parent) in memo.keys():
310
## state = copy.copy(state)
311
## state["parent"] = None
313
## s2 = copy.deepcopy(state, memo)
315
## if hasattr(clone, "__setstate__"): clone.__setstate__(s2)
316
## else: clone.__dict__ = s2
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.
328
## Most of the math operator, such as +, -, *, /, abs,... work on Vectors and do
329
## what they are intended to do ;-)
331
## Vector inherits from Point for practical reasons, since both have x, y, z
332
## coordinates and a parent."""
334
## def __init__(_self, _parent = None, _x = 0.0, _y = 0.0, _z = 0.0):
335
## _soya.Vector.__init__(_self, _parent, _x, _y, _z)
337
## def move(self, position):
338
## """Vector.move(position)
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
348
## self.x, self.y, self.z = self.parent.transform_vector(position.x, position.y, position.z, position.parent)
350
## def convert_to(self, parent):
351
## """Vector.convert_to(parent)
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
360
## """Vector.copy() -> Vector
362
## Returns a copy of a Vector."""
363
## return Vector(self.parent, self.x, self.y, self.z)
366
## def cross_product(self, vector):
367
## """Vector.cross_product(VECTOR) -> Vector
369
## Returns the cross product of a Vector with VECTOR."""
370
## return _soya.cross_vector(self, vector)
372
## def dot_product(self, vector):
373
## """Vector.dot_product(VECTOR) -> float
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
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
383
## """Vector.length() -> float
385
## Gets the length of a Vector."""
386
## return math.sqrt(self.x ** 2 + self.y ** 2 + self.z ** 2)
388
## def set_length(self, new_length):
389
## """Vector.set_length(new_length)
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()
398
## def __mod__(self, coordsyst):
399
## """Vector % coordsyst -> Vector
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."""
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)
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__
414
## def __imul__(self, number):
420
## def __idiv__(self, number):
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)
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)
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)
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)
440
## def __neg__(self): return Vector(self.parent, -self.x, -self.y, -self.z)
442
## def __abs__(self): return Vector(self.parent, abs(self.x), abs(self.y), abs(self.z))
444
## def normalize(self):
445
## """Vector.normalize()
447
## Normalizes a Vector IN PLACE."""
448
## length = self.length()
453
## def __repr__(self): return "<Vector %s, %s, %s in %s>" % (self.x, self.y, self.z, self.parent)
455
## def set_start_end(self, start, end):
456
## """Vector.set_start_end(start, end)
458
## Sets this vector IN PLACE so as it correspond to the vector start->end."""
459
## self.parent = start.parent
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
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
471
## def angle_to(self, vector):
472
## """Vector.angle_to(VECTOR) -> angle in degree
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
483
_soya.new_point = Point
484
_soya.new_vector = Vector
19
warnings.warn("The content of this module is now in the soya module.", DeprecationWarning)
21
from soya import Point, Vector