5
|
1 __version__ = "$Id$"
|
|
2 __docformat__ = "reStructuredText"
|
|
3
|
|
4 import operator
|
|
5 import math
|
|
6 import ctypes
|
|
7
|
|
8 class Vec2d(ctypes.Structure):
|
|
9 """2d vector class, supports vector and scalar operators,
|
|
10 and also provides a bunch of high level functions
|
|
11 """
|
|
12 __slots__ = ['x', 'y']
|
|
13
|
|
14 @classmethod
|
|
15 def from_param(cls, arg):
|
|
16 return cls(arg)
|
|
17
|
|
18 def __init__(self, x_or_pair, y = None):
|
|
19
|
|
20 if y == None:
|
|
21 self.x = x_or_pair[0]
|
|
22 self.y = x_or_pair[1]
|
|
23 else:
|
|
24 self.x = x_or_pair
|
|
25 self.y = y
|
|
26
|
|
27 def __len__(self):
|
|
28 return 2
|
|
29
|
|
30 def __getitem__(self, key):
|
|
31 if key == 0:
|
|
32 return self.x
|
|
33 elif key == 1:
|
|
34 return self.y
|
|
35 else:
|
|
36 raise IndexError("Invalid subscript "+str(key)+" to Vec2d")
|
|
37
|
|
38 def __setitem__(self, key, value):
|
|
39 if key == 0:
|
|
40 self.x = value
|
|
41 elif key == 1:
|
|
42 self.y = value
|
|
43 else:
|
|
44 raise IndexError("Invalid subscript "+str(key)+" to Vec2d")
|
|
45
|
|
46 # String representaion (for debugging)
|
|
47 def __repr__(self):
|
|
48 return 'Vec2d(%s, %s)' % (self.x, self.y)
|
|
49
|
|
50 # Comparison
|
|
51 def __eq__(self, other):
|
|
52 if hasattr(other, "__getitem__") and len(other) == 2:
|
|
53 return self.x == other[0] and self.y == other[1]
|
|
54 else:
|
|
55 return False
|
|
56
|
|
57 def __ne__(self, other):
|
|
58 if hasattr(other, "__getitem__") and len(other) == 2:
|
|
59 return self.x != other[0] or self.y != other[1]
|
|
60 else:
|
|
61 return True
|
|
62
|
|
63 def __nonzero__(self):
|
|
64 return self.x or self.y
|
|
65
|
|
66 # Generic operator handlers
|
|
67 def _o2(self, other, f):
|
|
68 "Any two-operator operation where the left operand is a Vec2d"
|
|
69 if isinstance(other, Vec2d):
|
|
70 return Vec2d(f(self.x, other.x),
|
|
71 f(self.y, other.y))
|
|
72 elif (hasattr(other, "__getitem__")):
|
|
73 return Vec2d(f(self.x, other[0]),
|
|
74 f(self.y, other[1]))
|
|
75 else:
|
|
76 return Vec2d(f(self.x, other),
|
|
77 f(self.y, other))
|
|
78
|
|
79 def _r_o2(self, other, f):
|
|
80 "Any two-operator operation where the right operand is a Vec2d"
|
|
81 if (hasattr(other, "__getitem__")):
|
|
82 return Vec2d(f(other[0], self.x),
|
|
83 f(other[1], self.y))
|
|
84 else:
|
|
85 return Vec2d(f(other, self.x),
|
|
86 f(other, self.y))
|
|
87
|
|
88 def _io(self, other, f):
|
|
89 "inplace operator"
|
|
90 if (hasattr(other, "__getitem__")):
|
|
91 self.x = f(self.x, other[0])
|
|
92 self.y = f(self.y, other[1])
|
|
93 else:
|
|
94 self.x = f(self.x, other)
|
|
95 self.y = f(self.y, other)
|
|
96 return self
|
|
97
|
|
98 # Addition
|
|
99 def __add__(self, other):
|
|
100 if isinstance(other, Vec2d):
|
|
101 return Vec2d(self.x + other.x, self.y + other.y)
|
|
102 elif hasattr(other, "__getitem__"):
|
|
103 return Vec2d(self.x + other[0], self.y + other[1])
|
|
104 else:
|
|
105 return Vec2d(self.x + other, self.y + other)
|
|
106 __radd__ = __add__
|
|
107
|
|
108 def __iadd__(self, other):
|
|
109 if isinstance(other, Vec2d):
|
|
110 self.x += other.x
|
|
111 self.y += other.y
|
|
112 elif hasattr(other, "__getitem__"):
|
|
113 self.x += other[0]
|
|
114 self.y += other[1]
|
|
115 else:
|
|
116 self.x += other
|
|
117 self.y += other
|
|
118 return self
|
|
119
|
|
120 # Subtraction
|
|
121 def __sub__(self, other):
|
|
122 if isinstance(other, Vec2d):
|
|
123 return Vec2d(self.x - other.x, self.y - other.y)
|
|
124 elif (hasattr(other, "__getitem__")):
|
|
125 return Vec2d(self.x - other[0], self.y - other[1])
|
|
126 else:
|
|
127 return Vec2d(self.x - other, self.y - other)
|
|
128 def __rsub__(self, other):
|
|
129 if isinstance(other, Vec2d):
|
|
130 return Vec2d(other.x - self.x, other.y - self.y)
|
|
131 if (hasattr(other, "__getitem__")):
|
|
132 return Vec2d(other[0] - self.x, other[1] - self.y)
|
|
133 else:
|
|
134 return Vec2d(other - self.x, other - self.y)
|
|
135 def __isub__(self, other):
|
|
136 if isinstance(other, Vec2d):
|
|
137 self.x -= other.x
|
|
138 self.y -= other.y
|
|
139 elif (hasattr(other, "__getitem__")):
|
|
140 self.x -= other[0]
|
|
141 self.y -= other[1]
|
|
142 else:
|
|
143 self.x -= other
|
|
144 self.y -= other
|
|
145 return self
|
|
146
|
|
147 # Multiplication
|
|
148 def __mul__(self, other):
|
|
149 if isinstance(other, Vec2d):
|
|
150 return Vec2d(self.x*other.y, self.y*other.y)
|
|
151 if (hasattr(other, "__getitem__")):
|
|
152 return Vec2d(self.x*other[0], self.y*other[1])
|
|
153 else:
|
|
154 return Vec2d(self.x*other, self.y*other)
|
|
155 __rmul__ = __mul__
|
|
156
|
|
157 def __imul__(self, other):
|
|
158 if isinstance(other, Vec2d):
|
|
159 self.x *= other.x
|
|
160 self.y *= other.y
|
|
161 elif (hasattr(other, "__getitem__")):
|
|
162 self.x *= other[0]
|
|
163 self.y *= other[1]
|
|
164 else:
|
|
165 self.x *= other
|
|
166 self.y *= other
|
|
167 return self
|
|
168
|
|
169 # Division
|
|
170 def __div__(self, other):
|
|
171 return self._o2(other, operator.div)
|
|
172 def __rdiv__(self, other):
|
|
173 return self._r_o2(other, operator.div)
|
|
174 def __idiv__(self, other):
|
|
175 return self._io(other, operator.div)
|
|
176
|
|
177 def __floordiv__(self, other):
|
|
178 return self._o2(other, operator.floordiv)
|
|
179 def __rfloordiv__(self, other):
|
|
180 return self._r_o2(other, operator.floordiv)
|
|
181 def __ifloordiv__(self, other):
|
|
182 return self._io(other, operator.floordiv)
|
|
183
|
|
184 def __truediv__(self, other):
|
|
185 return self._o2(other, operator.truediv)
|
|
186 def __rtruediv__(self, other):
|
|
187 return self._r_o2(other, operator.truediv)
|
|
188 def __itruediv__(self, other):
|
|
189 return self._io(other, operator.floordiv)
|
|
190
|
|
191 # Modulo
|
|
192 def __mod__(self, other):
|
|
193 return self._o2(other, operator.mod)
|
|
194 def __rmod__(self, other):
|
|
195 return self._r_o2(other, operator.mod)
|
|
196
|
|
197 def __divmod__(self, other):
|
|
198 return self._o2(other, divmod)
|
|
199 def __rdivmod__(self, other):
|
|
200 return self._r_o2(other, divmod)
|
|
201
|
|
202 # Exponentation
|
|
203 def __pow__(self, other):
|
|
204 return self._o2(other, operator.pow)
|
|
205 def __rpow__(self, other):
|
|
206 return self._r_o2(other, operator.pow)
|
|
207
|
|
208 # Bitwise operators
|
|
209 def __lshift__(self, other):
|
|
210 return self._o2(other, operator.lshift)
|
|
211 def __rlshift__(self, other):
|
|
212 return self._r_o2(other, operator.lshift)
|
|
213
|
|
214 def __rshift__(self, other):
|
|
215 return self._o2(other, operator.rshift)
|
|
216 def __rrshift__(self, other):
|
|
217 return self._r_o2(other, operator.rshift)
|
|
218
|
|
219 def __and__(self, other):
|
|
220 return self._o2(other, operator.and_)
|
|
221 __rand__ = __and__
|
|
222
|
|
223 def __or__(self, other):
|
|
224 return self._o2(other, operator.or_)
|
|
225 __ror__ = __or__
|
|
226
|
|
227 def __xor__(self, other):
|
|
228 return self._o2(other, operator.xor)
|
|
229 __rxor__ = __xor__
|
|
230
|
|
231 # Unary operations
|
|
232 def __neg__(self):
|
|
233 return Vec2d(operator.neg(self.x), operator.neg(self.y))
|
|
234
|
|
235 def __pos__(self):
|
|
236 return Vec2d(operator.pos(self.x), operator.pos(self.y))
|
|
237
|
|
238 def __abs__(self):
|
|
239 return Vec2d(abs(self.x), abs(self.y))
|
|
240
|
|
241 def __invert__(self):
|
|
242 return Vec2d(-self.x, -self.y)
|
|
243
|
|
244 # vectory functions
|
|
245 def get_length_sqrd(self):
|
|
246 """Get the squared length of the vector.
|
|
247 It is more efficent to use this method instead of first call
|
|
248 get_length() or access .length and then do a sqrt().
|
|
249
|
|
250 :return: The squared length
|
|
251 """
|
|
252 return self.x**2 + self.y**2
|
|
253
|
|
254 def get_length(self):
|
|
255 """Get the length of the vector.
|
|
256
|
|
257 :return: The length
|
|
258 """
|
|
259 return math.sqrt(self.x**2 + self.y**2)
|
|
260 def __setlength(self, value):
|
|
261 length = self.get_length()
|
|
262 self.x *= value/length
|
|
263 self.y *= value/length
|
|
264 length = property(get_length, __setlength, doc = """Gets or sets the magnitude of the vector""")
|
|
265
|
|
266 def rotate(self, angle_degrees):
|
|
267 """Rotate the vector by angle_degrees degrees clockwise."""
|
|
268 radians = -math.radians(angle_degrees)
|
|
269 cos = math.cos(radians)
|
|
270 sin = math.sin(radians)
|
|
271 x = self.x*cos - self.y*sin
|
|
272 y = self.x*sin + self.y*cos
|
|
273 self.x = x
|
|
274 self.y = y
|
|
275
|
|
276 def rotated(self, angle_degrees):
|
|
277 """Create and return a new vector by rotating this vector by
|
|
278 angle_degrees degrees clockwise.
|
|
279
|
|
280 :return: Rotated vector
|
|
281 """
|
|
282 radians = -math.radians(angle_degrees)
|
|
283 cos = math.cos(radians)
|
|
284 sin = math.sin(radians)
|
|
285 x = self.x*cos - self.y*sin
|
|
286 y = self.x*sin + self.y*cos
|
|
287 return Vec2d(x, y)
|
|
288
|
|
289 def get_angle(self):
|
|
290 if (self.get_length_sqrd() == 0):
|
|
291 return 0
|
|
292 return math.degrees(math.atan2(self.y, self.x))
|
|
293 def __setangle(self, angle_degrees):
|
|
294 self.x = self.length
|
|
295 self.y = 0
|
|
296 self.rotate(angle_degrees)
|
|
297 angle = property(get_angle, __setangle, doc="""Gets or sets the angle of a vector""")
|
|
298
|
|
299 def get_angle_between(self, other):
|
|
300 """Get the angle between the vector and the other in degrees
|
|
301
|
|
302 :return: The angle
|
|
303 """
|
|
304 cross = self.x*other[1] - self.y*other[0]
|
|
305 dot = self.x*other[0] + self.y*other[1]
|
|
306 return math.degrees(math.atan2(cross, dot))
|
|
307
|
|
308 def normalized(self):
|
|
309 """Get a normalized copy of the vector
|
|
310
|
|
311 :return: A normalized vector
|
|
312 """
|
|
313 length = self.length
|
|
314 if length != 0:
|
|
315 return self/length
|
|
316 return Vec2d(self)
|
|
317
|
|
318 def normalize_return_length(self):
|
|
319 """Normalize the vector and return its length before the normalization
|
|
320
|
|
321 :return: The length before the normalization
|
|
322 """
|
|
323 length = self.length
|
|
324 if length != 0:
|
|
325 self.x /= length
|
|
326 self.y /= length
|
|
327 return length
|
|
328
|
|
329 def perpendicular(self):
|
|
330 return Vec2d(-self.y, self.x)
|
|
331
|
|
332 def perpendicular_normal(self):
|
|
333 length = self.length
|
|
334 if length != 0:
|
|
335 return Vec2d(-self.y/length, self.x/length)
|
|
336 return Vec2d(self)
|
|
337
|
|
338 def dot(self, other):
|
|
339 """The dot product between the vector and other vector
|
|
340 v1.dot(v2) -> v1.x*v2.x + v1.y*v2.y
|
|
341
|
|
342 :return: The dot product
|
|
343 """
|
|
344 return float(self.x*other[0] + self.y*other[1])
|
|
345
|
|
346 def get_distance(self, other):
|
|
347 """The distance between the vector and other vector
|
|
348
|
|
349 :return: The distance
|
|
350 """
|
|
351 return math.sqrt((self.x - other[0])**2 + (self.y - other[1])**2)
|
|
352
|
|
353 def get_dist_sqrd(self, other):
|
|
354 """The squared distance between the vector and other vector
|
|
355 It is more efficent to use this method than to call get_distance()
|
|
356 first and then do a sqrt() on the result.
|
|
357
|
|
358 :return: The squared distance
|
|
359 """
|
|
360 return (self.x - other[0])**2 + (self.y - other[1])**2
|
|
361
|
|
362 def projection(self, other):
|
|
363 other_length_sqrd = other[0]*other[0] + other[1]*other[1]
|
|
364 projected_length_times_other_length = self.dot(other)
|
|
365 return other*(projected_length_times_other_length/other_length_sqrd)
|
|
366
|
|
367 def cross(self, other):
|
|
368 """The cross product between the vector and other vector
|
|
369 v1.cross(v2) -> v1.x*v2.y - v2.y-v1.x
|
|
370
|
|
371 :return: The cross product
|
|
372 """
|
|
373 return self.x*other[1] - self.y*other[0]
|
|
374
|
|
375 def interpolate_to(self, other, range):
|
|
376 return Vec2d(self.x + (other[0] - self.x)*range, self.y + (other[1] - self.y)*range)
|
|
377
|
|
378 def convert_to_basis(self, x_vector, y_vector):
|
|
379 return Vec2d(self.dot(x_vector)/x_vector.get_length_sqrd(), self.dot(y_vector)/y_vector.get_length_sqrd())
|
|
380
|
|
381 # Extra functions, mainly for chipmunk
|
|
382 def cpvrotate(self, other):
|
|
383 return Vec2d(self.x*other.x - self.y*other.y, self.x*other.y + self.y*other.x)
|
|
384 def cpvunrotate(self, other):
|
|
385 return Vec2d(self.x*other.x + self.y*other.y, self.y*other.x - self.x*other.y)
|
|
386
|
|
387 # Pickle, does not work atm.
|
|
388 def __getstate__(self):
|
|
389 return [self.x, self.y]
|
|
390
|
|
391 def __setstate__(self, dict):
|
|
392 self.x, self.y = dict
|
|
393 def __newobj__(cls, *args):
|
|
394 return cls.__new__(cls, *args)
|
|
395 Vec2d._fields_ = [
|
|
396 ('x', ctypes.c_double),
|
|
397 ('y', ctypes.c_double),
|
|
398 ]
|
|
399
|
|
400
|
|
401 class Vec2dArray(list):
|
|
402
|
|
403 def __init__(self, iterable=()):
|
|
404 list.__init__(self, (Vec2d(i) for i in iterable))
|
|
405
|
|
406 def __setitem__(self, index, value):
|
|
407 list.__setitem__(self, index, Vec2d(value))
|
|
408
|
|
409 def append(self, value):
|
|
410 """Append a vector to the array"""
|
|
411 list.append(self, Vec2d(value))
|
|
412
|
|
413 def insert(self, index, value):
|
|
414 """Insert a vector into the array"""
|
|
415 list.insert(self, index, Vec2d(value))
|
|
416
|
|
417 def transform(self, offset=Vec2d(0,0), angle=0, scale=1.0):
|
|
418 """Return a new transformed Vec2dArray"""
|
|
419 offset = Vec2d(offset)
|
|
420 angle = math.radians(-angle)
|
|
421 rot_vec = Vec2d(math.cos(angle), math.sin(angle))
|
|
422 xformed = Vec2dArray()
|
|
423 for vec in self:
|
|
424 xformed.append(vec.cpvrotate(rot_vec) * scale + offset)
|
|
425 return xformed
|
|
426
|
|
427 def segments(self, closed=True):
|
|
428 """Generate arrays of line segments connecting adjacent vetices
|
|
429 in this array, exploding the shape into it's constituent segments
|
|
430 """
|
|
431 if len(self) >= 2:
|
|
432 last = self[0]
|
|
433 for vert in self[1:]:
|
|
434 yield Vec2dArray((last, vert))
|
|
435 last = vert
|
|
436 if closed:
|
|
437 yield Vec2dArray((last, self[0]))
|
|
438 elif self and closed:
|
|
439 yield Vec2dArray((self[0], self[0]))
|
|
440
|
|
441
|
|
442
|
|
443 class Rect(ctypes.Structure):
|
|
444 """Simple rectangle. Will gain more functionality as needed"""
|
|
445 _fields_ = [
|
|
446 ('left', ctypes.c_double),
|
|
447 ('top', ctypes.c_double),
|
|
448 ('right', ctypes.c_double),
|
|
449 ('bottom', ctypes.c_double),
|
|
450 ]
|
|
451
|
|
452 def __init__(self, rect_or_left, bottom=None, right=None, top=None):
|
|
453 if bottom is not None:
|
|
454 assert right is not None and top is not None, "No enough arguments to Rect"
|
|
455 self.left = rect_or_left
|
|
456 self.bottom = bottom
|
|
457 self.right = right
|
|
458 self.top = top
|
|
459 else:
|
|
460 self.left = rect_or_left.left
|
|
461 self.bottom = rect_or_left.bottom
|
|
462 self.right = rect_or_left.right
|
|
463 self.top = rect_or_left.top
|
|
464
|
|
465 @property
|
|
466 def width(self):
|
|
467 """Rectangle width"""
|
|
468 return self.right - self.left
|
|
469
|
|
470 @property
|
|
471 def height(self):
|
|
472 """Rectangle height"""
|
|
473 return self.top - self.bottom
|
|
474
|
|
475
|
|
476 ########################################################################
|
|
477 ## Unit Testing ##
|
|
478 ########################################################################
|
|
479 if __name__ == "__main__":
|
|
480
|
|
481 import unittest
|
|
482 import pickle
|
|
483
|
|
484 ####################################################################
|
|
485 class UnitTestVec2d(unittest.TestCase):
|
|
486
|
|
487 def setUp(self):
|
|
488 pass
|
|
489
|
|
490 def testCreationAndAccess(self):
|
|
491 v = Vec2d(111, 222)
|
|
492 self.assert_(v.x == 111 and v.y == 222)
|
|
493 v.x = 333
|
|
494 v[1] = 444
|
|
495 self.assert_(v[0] == 333 and v[1] == 444)
|
|
496
|
|
497 def testMath(self):
|
|
498 v = Vec2d(111,222)
|
|
499 self.assertEqual(v + 1, Vec2d(112, 223))
|
|
500 self.assert_(v - 2 == [109, 220])
|
|
501 self.assert_(v * 3 == (333, 666))
|
|
502 self.assert_(v / 2.0 == Vec2d(55.5, 111))
|
|
503 #self.assert_(v / 2 == (55, 111)) # Not supported since this is a c_float structure in the bottom
|
|
504 self.assert_(v ** Vec2d(2, 3) == [12321, 10941048])
|
|
505 self.assert_(v + [-11, 78] == Vec2d(100, 300))
|
|
506 #self.assert_(v / [11,2] == [10,111]) # Not supported since this is a c_float structure in the bottom
|
|
507
|
|
508 def testReverseMath(self):
|
|
509 v = Vec2d(111, 222)
|
|
510 self.assert_(1 + v == Vec2d(112, 223))
|
|
511 self.assert_(2 - v == [-109, -220])
|
|
512 self.assert_(3 * v == (333, 666))
|
|
513 #self.assert_([222,999] / v == [2,4]) # Not supported since this is a c_float structure in the bottom
|
|
514 self.assert_([111, 222] ** Vec2d(2, 3) == [12321, 10941048])
|
|
515 self.assert_([-11, 78] + v == Vec2d(100, 300))
|
|
516
|
|
517 def testUnary(self):
|
|
518 v = Vec2d(111, 222)
|
|
519 v = -v
|
|
520 self.assert_(v == [-111, -222])
|
|
521 v = abs(v)
|
|
522 self.assert_(v == [111, 222])
|
|
523
|
|
524 def testLength(self):
|
|
525 v = Vec2d(3,4)
|
|
526 self.assert_(v.length == 5)
|
|
527 self.assert_(v.get_length_sqrd() == 25)
|
|
528 self.assert_(v.normalize_return_length() == 5)
|
|
529 self.assertAlmostEquals(v.length, 1)
|
|
530 v.length = 5
|
|
531 self.assert_(v == Vec2d(3, 4))
|
|
532 v2 = Vec2d(10, -2)
|
|
533 self.assert_(v.get_distance(v2) == (v - v2).get_length())
|
|
534
|
|
535 def testAngles(self):
|
|
536 v = Vec2d(0, 3)
|
|
537 self.assertEquals(v.angle, 90)
|
|
538 v2 = Vec2d(v)
|
|
539 v.rotate(-90)
|
|
540 self.assertEqual(v.get_angle_between(v2), 90)
|
|
541 v2.angle -= 90
|
|
542 self.assertEqual(v.length, v2.length)
|
|
543 self.assertEquals(v2.angle, 0)
|
|
544 self.assertEqual(v2, [3, 0])
|
|
545 self.assert_((v - v2).length < .00001)
|
|
546 self.assertEqual(v.length, v2.length)
|
|
547 v2.rotate(300)
|
|
548 self.assertAlmostEquals(v.get_angle_between(v2), -60, 5) # Allow a little more error than usual (floats..)
|
|
549 v2.rotate(v2.get_angle_between(v))
|
|
550 angle = v.get_angle_between(v2)
|
|
551 self.assertAlmostEquals(v.get_angle_between(v2), 0)
|
|
552
|
|
553 def testHighLevel(self):
|
|
554 basis0 = Vec2d(5.0, 0)
|
|
555 basis1 = Vec2d(0, .5)
|
|
556 v = Vec2d(10, 1)
|
|
557 self.assert_(v.convert_to_basis(basis0, basis1) == [2, 2])
|
|
558 self.assert_(v.projection(basis0) == (10, 0))
|
|
559 self.assert_(basis0.dot(basis1) == 0)
|
|
560
|
|
561 def testCross(self):
|
|
562 lhs = Vec2d(1, .5)
|
|
563 rhs = Vec2d(4, 6)
|
|
564 self.assert_(lhs.cross(rhs) == 4)
|
|
565
|
|
566 def testComparison(self):
|
|
567 int_vec = Vec2d(3, -2)
|
|
568 flt_vec = Vec2d(3.0, -2.0)
|
|
569 zero_vec = Vec2d(0, 0)
|
|
570 self.assert_(int_vec == flt_vec)
|
|
571 self.assert_(int_vec != zero_vec)
|
|
572 self.assert_((flt_vec == zero_vec) == False)
|
|
573 self.assert_((flt_vec != int_vec) == False)
|
|
574 self.assert_(int_vec == (3, -2))
|
|
575 self.assert_(int_vec != [0, 0])
|
|
576 self.assert_(int_vec != 5)
|
|
577 self.assert_(int_vec != [3, -2, -5])
|
|
578
|
|
579 def testInplace(self):
|
|
580 inplace_vec = Vec2d(5, 13)
|
|
581 inplace_ref = inplace_vec
|
|
582 inplace_src = Vec2d(inplace_vec)
|
|
583 inplace_vec *= .5
|
|
584 inplace_vec += .5
|
|
585 inplace_vec /= (3, 6)
|
|
586 inplace_vec += Vec2d(-1, -1)
|
|
587 alternate = (inplace_src*.5 + .5)/Vec2d(3, 6) + [-1, -1]
|
|
588 self.assertEquals(inplace_vec, inplace_ref)
|
|
589 self.assertEquals(inplace_vec, alternate)
|
|
590
|
|
591 def testPickle(self):
|
|
592 return # pickling does not work atm
|
|
593 testvec = Vec2d(5, .3)
|
|
594 testvec_str = pickle.dumps(testvec)
|
|
595 loaded_vec = pickle.loads(testvec_str)
|
|
596 self.assertEquals(testvec, loaded_vec)
|
|
597
|
|
598 ####################################################################
|
|
599 unittest.main()
|
|
600
|