1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 import operator
47 import math
48
50 """2d vector class, supports vector and scalar operators,
51 and also provides a bunch of high level functions
52 """
53 __slots__ = ['x', 'y']
54
55 - def __init__(self, x_or_pair, y = None):
56 if y == None:
57 self.x = x_or_pair[0]
58 self.y = x_or_pair[1]
59 else:
60 self.x = x_or_pair
61 self.y = y
62
65
67 if key == 0:
68 return self.x
69 elif key == 1:
70 return self.y
71 else:
72 raise IndexError("Invalid subscript "+str(key)+" to Vec2d")
73
75 if key == 0:
76 self.x = value
77 elif key == 1:
78 self.y = value
79 else:
80 raise IndexError("Invalid subscript "+str(key)+" to Vec2d")
81
82
84 return 'Vec2d(%s, %s)' % (self.x, self.y)
85
86
88 if hasattr(other, "__getitem__") and len(other) == 2:
89 return self.x == other[0] and self.y == other[1]
90 else:
91 return False
92
94 if hasattr(other, "__getitem__") and len(other) == 2:
95 return self.x != other[0] or self.y != other[1]
96 else:
97 return True
98
100 return bool(self.x or self.y)
101
102
103 - def _o2(self, other, f):
104 "Any two-operator operation where the left operand is a Vec2d"
105 if isinstance(other, Vec2d):
106 return Vec2d(f(self.x, other.x),
107 f(self.y, other.y))
108 elif (hasattr(other, "__getitem__")):
109 return Vec2d(f(self.x, other[0]),
110 f(self.y, other[1]))
111 else:
112 return Vec2d(f(self.x, other),
113 f(self.y, other))
114
115 - def _r_o2(self, other, f):
116 "Any two-operator operation where the right operand is a Vec2d"
117 if (hasattr(other, "__getitem__")):
118 return Vec2d(f(other[0], self.x),
119 f(other[1], self.y))
120 else:
121 return Vec2d(f(other, self.x),
122 f(other, self.y))
123
124 - def _io(self, other, f):
125 "inplace operator"
126 if (hasattr(other, "__getitem__")):
127 self.x = f(self.x, other[0])
128 self.y = f(self.y, other[1])
129 else:
130 self.x = f(self.x, other)
131 self.y = f(self.y, other)
132 return self
133
134
136 if isinstance(other, Vec2d):
137 return Vec2d(self.x + other.x, self.y + other.y)
138 elif hasattr(other, "__getitem__"):
139 return Vec2d(self.x + other[0], self.y + other[1])
140 else:
141 return Vec2d(self.x + other, self.y + other)
142 __radd__ = __add__
143
145 if isinstance(other, Vec2d):
146 self.x += other.x
147 self.y += other.y
148 elif hasattr(other, "__getitem__"):
149 self.x += other[0]
150 self.y += other[1]
151 else:
152 self.x += other
153 self.y += other
154 return self
155
156
158 if isinstance(other, Vec2d):
159 return Vec2d(self.x - other.x, self.y - other.y)
160 elif (hasattr(other, "__getitem__")):
161 return Vec2d(self.x - other[0], self.y - other[1])
162 else:
163 return Vec2d(self.x - other, self.y - other)
165 if isinstance(other, Vec2d):
166 return Vec2d(other.x - self.x, other.y - self.y)
167 if (hasattr(other, "__getitem__")):
168 return Vec2d(other[0] - self.x, other[1] - self.y)
169 else:
170 return Vec2d(other - self.x, other - self.y)
172 if isinstance(other, Vec2d):
173 self.x -= other.x
174 self.y -= other.y
175 elif (hasattr(other, "__getitem__")):
176 self.x -= other[0]
177 self.y -= other[1]
178 else:
179 self.x -= other
180 self.y -= other
181 return self
182
183
185 if isinstance(other, Vec2d):
186 return Vec2d(self.x*other.x, self.y*other.y)
187 if (hasattr(other, "__getitem__")):
188 return Vec2d(self.x*other[0], self.y*other[1])
189 else:
190 return Vec2d(self.x*other, self.y*other)
191 __rmul__ = __mul__
192
194 if isinstance(other, Vec2d):
195 self.x *= other.x
196 self.y *= other.y
197 elif (hasattr(other, "__getitem__")):
198 self.x *= other[0]
199 self.y *= other[1]
200 else:
201 self.x *= other
202 self.y *= other
203 return self
204
205
207 return self._o2(other, operator.div)
209 return self._r_o2(other, operator.div)
211 return self._io(other, operator.div)
212
214 return self._o2(other, operator.floordiv)
216 return self._r_o2(other, operator.floordiv)
218 return self._io(other, operator.floordiv)
219
221 return self._o2(other, operator.truediv)
223 return self._r_o2(other, operator.truediv)
225 return self._io(other, operator.floordiv)
226
227
229 return self._o2(other, operator.mod)
231 return self._r_o2(other, operator.mod)
232
234 return self._o2(other, operator.divmod)
236 return self._r_o2(other, operator.divmod)
237
238
240 return self._o2(other, operator.pow)
242 return self._r_o2(other, operator.pow)
243
244
246 return self._o2(other, operator.lshift)
248 return self._r_o2(other, operator.lshift)
249
251 return self._o2(other, operator.rshift)
253 return self._r_o2(other, operator.rshift)
254
256 return self._o2(other, operator.and_)
257 __rand__ = __and__
258
260 return self._o2(other, operator.or_)
261 __ror__ = __or__
262
264 return self._o2(other, operator.xor)
265 __rxor__ = __xor__
266
267
269 return Vec2d(operator.neg(self.x), operator.neg(self.y))
270
272 return Vec2d(operator.pos(self.x), operator.pos(self.y))
273
275 return Vec2d(abs(self.x), abs(self.y))
276
279
280
282 return self.x**2 + self.y**2
283
285 return math.sqrt(self.x**2 + self.y**2)
290 length = property(get_length, __setlength, None, "gets or sets the magnitude of the vector")
291
292 - def rotate(self, angle_degrees):
300
308
314 self.x = self.length
315 self.y = 0
316 self.rotate(angle_degrees)
317 angle = property(get_angle, __setangle, None, "gets or sets the angle of a vector")
318
320 cross = self.x*other[1] - self.y*other[0]
321 dot = self.x*other[0] + self.y*other[1]
322 return math.degrees(math.atan2(cross, dot))
323
329
336
339
345
346 - def dot(self, other):
347 return float(self.x*other[0] + self.y*other[1])
348
350 return math.sqrt((self.x - other[0])**2 + (self.y - other[1])**2)
351
353 return (self.x - other[0])**2 + (self.y - other[1])**2
354
356 other_length_sqrd = other[0]*other[0] + other[1]*other[1]
357 projected_length_times_other_length = self.dot(other)
358 return other*(projected_length_times_other_length/other_length_sqrd)
359
361 return self.x*other[1] - self.y*other[0]
362
364 return Vec2d(self.x + (other[0] - self.x)*range, self.y + (other[1] - self.y)*range)
365
368
370 return [self.x, self.y]
371
373 self.x, self.y = dict
374
375
376
377
378 if __name__ == "__main__":
379
380 import unittest
381 import pickle
382
383
385
388
390 v = Vec2d(111,222)
391 self.assert_(v.x == 111 and v.y == 222)
392 v.x = 333
393 v[1] = 444
394 self.assert_(v[0] == 333 and v[1] == 444)
395
397 v = Vec2d(111,222)
398 self.assertEqual(v + 1, Vec2d(112,223))
399 self.assert_(v - 2 == [109,220])
400 self.assert_(v * 3 == (333,666))
401 self.assert_(v / 2.0 == Vec2d(55.5, 111))
402 self.assert_(v / 2 == (55.5, 111))
403 self.assert_(v ** Vec2d(2,3) == [12321, 10941048])
404 self.assert_(v + [-11, 78] == Vec2d(100, 300))
405 self.assert_(v / [10,2] == [11.1,111])
406
408 v = Vec2d(111,222)
409 self.assert_(1 + v == Vec2d(112,223))
410 self.assert_(2 - v == [-109,-220])
411 self.assert_(3 * v == (333,666))
412 self.assert_([222,888] / v == [2,4])
413 self.assert_([111,222] ** Vec2d(2,3) == [12321, 10941048])
414 self.assert_([-11, 78] + v == Vec2d(100, 300))
415
417 v = Vec2d(111,222)
418 v = -v
419 self.assert_(v == [-111,-222])
420 v = abs(v)
421 self.assert_(v == [111,222])
422
433
435 v = Vec2d(0, 3)
436 self.assertEquals(v.angle, 90)
437 v2 = Vec2d(v)
438 v.rotate(-90)
439 self.assertEqual(v.get_angle_between(v2), 90)
440 v2.angle -= 90
441 self.assertEqual(v.length, v2.length)
442 self.assertEquals(v2.angle, 0)
443 self.assertEqual(v2, [3, 0])
444 self.assert_((v - v2).length < .00001)
445 self.assertEqual(v.length, v2.length)
446 v2.rotate(300)
447 self.assertAlmostEquals(v.get_angle_between(v2), -60)
448 v2.rotate(v2.get_angle_between(v))
449 angle = v.get_angle_between(v2)
450 self.assertAlmostEquals(v.get_angle_between(v2), 0)
451
453 basis0 = Vec2d(5.0, 0)
454 basis1 = Vec2d(0, .5)
455 v = Vec2d(10, 1)
456 self.assert_(v.convert_to_basis(basis0, basis1) == [2, 2])
457 self.assert_(v.projection(basis0) == (10, 0))
458 self.assert_(basis0.dot(basis1) == 0)
459
461 lhs = Vec2d(1, .5)
462 rhs = Vec2d(4,6)
463 self.assert_(lhs.cross(rhs) == 4)
464
466 int_vec = Vec2d(3, -2)
467 flt_vec = Vec2d(3.0, -2.0)
468 zero_vec = Vec2d(0, 0)
469 self.assert_(int_vec == flt_vec)
470 self.assert_(int_vec != zero_vec)
471 self.assert_((flt_vec == zero_vec) == False)
472 self.assert_((flt_vec != int_vec) == False)
473 self.assert_(int_vec == (3, -2))
474 self.assert_(int_vec != [0, 0])
475 self.assert_(int_vec != 5)
476 self.assert_(int_vec != [3, -2, -5])
477
479 inplace_vec = Vec2d(5, 13)
480 inplace_ref = inplace_vec
481 inplace_src = Vec2d(inplace_vec)
482 inplace_vec *= .5
483 inplace_vec += .5
484 inplace_vec /= (3, 6)
485 inplace_vec += Vec2d(-1, -1)
486 self.assertEquals(inplace_vec, inplace_ref)
487
489 testvec = Vec2d(5, .3)
490 testvec_str = pickle.dumps(testvec)
491 loaded_vec = pickle.loads(testvec_str)
492 self.assertEquals(testvec, loaded_vec)
493
494
495 unittest.main()
496
497
498