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 import operator
44 import math
45
47 """2d vector class, supports vector and scalar operators,
48 and also provides a bunch of high level functions
49 """
50 __slots__ = ['x', 'y']
51
52 - def __init__(self, x_or_pair, y = None):
53 if y == None:
54 self.x = x_or_pair[0]
55 self.y = x_or_pair[1]
56 else:
57 self.x = x_or_pair
58 self.y = y
59
62
64 if key == 0:
65 return self.x
66 elif key == 1:
67 return self.y
68 else:
69 raise IndexError("Invalid subscript "+str(key)+" to Vec2d")
70
72 if key == 0:
73 self.x = value
74 elif key == 1:
75 self.y = value
76 else:
77 raise IndexError("Invalid subscript "+str(key)+" to Vec2d")
78
79
81 return 'Vec2d(%s, %s)' % (self.x, self.y)
82
83
85 if hasattr(other, "__getitem__") and len(other) == 2:
86 return self.x == other[0] and self.y == other[1]
87 else:
88 return False
89
91 if hasattr(other, "__getitem__") and len(other) == 2:
92 return self.x != other[0] or self.y != other[1]
93 else:
94 return True
95
97 return bool(self.x or self.y)
98
99
100 - def _o2(self, other, f):
101 "Any two-operator operation where the left operand is a Vec2d"
102 if isinstance(other, Vec2d):
103 return Vec2d(f(self.x, other.x),
104 f(self.y, other.y))
105 elif (hasattr(other, "__getitem__")):
106 return Vec2d(f(self.x, other[0]),
107 f(self.y, other[1]))
108 else:
109 return Vec2d(f(self.x, other),
110 f(self.y, other))
111
112 - def _r_o2(self, other, f):
113 "Any two-operator operation where the right operand is a Vec2d"
114 if (hasattr(other, "__getitem__")):
115 return Vec2d(f(other[0], self.x),
116 f(other[1], self.y))
117 else:
118 return Vec2d(f(other, self.x),
119 f(other, self.y))
120
121 - def _io(self, other, f):
122 "inplace operator"
123 if (hasattr(other, "__getitem__")):
124 self.x = f(self.x, other[0])
125 self.y = f(self.y, other[1])
126 else:
127 self.x = f(self.x, other)
128 self.y = f(self.y, other)
129 return self
130
131
133 if isinstance(other, Vec2d):
134 return Vec2d(self.x + other.x, self.y + other.y)
135 elif hasattr(other, "__getitem__"):
136 return Vec2d(self.x + other[0], self.y + other[1])
137 else:
138 return Vec2d(self.x + other, self.y + other)
139 __radd__ = __add__
140
142 if isinstance(other, Vec2d):
143 self.x += other.x
144 self.y += other.y
145 elif hasattr(other, "__getitem__"):
146 self.x += other[0]
147 self.y += other[1]
148 else:
149 self.x += other
150 self.y += other
151 return self
152
153
155 if isinstance(other, Vec2d):
156 return Vec2d(self.x - other.x, self.y - other.y)
157 elif (hasattr(other, "__getitem__")):
158 return Vec2d(self.x - other[0], self.y - other[1])
159 else:
160 return Vec2d(self.x - other, self.y - other)
162 if isinstance(other, Vec2d):
163 return Vec2d(other.x - self.x, other.y - self.y)
164 if (hasattr(other, "__getitem__")):
165 return Vec2d(other[0] - self.x, other[1] - self.y)
166 else:
167 return Vec2d(other - self.x, other - self.y)
169 if isinstance(other, Vec2d):
170 self.x -= other.x
171 self.y -= other.y
172 elif (hasattr(other, "__getitem__")):
173 self.x -= other[0]
174 self.y -= other[1]
175 else:
176 self.x -= other
177 self.y -= other
178 return self
179
180
182 if isinstance(other, Vec2d):
183 return Vec2d(self.x*other.x, self.y*other.y)
184 if (hasattr(other, "__getitem__")):
185 return Vec2d(self.x*other[0], self.y*other[1])
186 else:
187 return Vec2d(self.x*other, self.y*other)
188 __rmul__ = __mul__
189
191 if isinstance(other, Vec2d):
192 self.x *= other.x
193 self.y *= other.y
194 elif (hasattr(other, "__getitem__")):
195 self.x *= other[0]
196 self.y *= other[1]
197 else:
198 self.x *= other
199 self.y *= other
200 return self
201
202
204 return self._o2(other, operator.div)
206 return self._r_o2(other, operator.div)
208 return self._io(other, operator.div)
209
211 return self._o2(other, operator.floordiv)
213 return self._r_o2(other, operator.floordiv)
215 return self._io(other, operator.floordiv)
216
218 return self._o2(other, operator.truediv)
220 return self._r_o2(other, operator.truediv)
222 return self._io(other, operator.floordiv)
223
224
226 return self._o2(other, operator.mod)
228 return self._r_o2(other, operator.mod)
229
231 return self._o2(other, operator.divmod)
233 return self._r_o2(other, operator.divmod)
234
235
237 return self._o2(other, operator.pow)
239 return self._r_o2(other, operator.pow)
240
241
243 return self._o2(other, operator.lshift)
245 return self._r_o2(other, operator.lshift)
246
248 return self._o2(other, operator.rshift)
250 return self._r_o2(other, operator.rshift)
251
253 return self._o2(other, operator.and_)
254 __rand__ = __and__
255
257 return self._o2(other, operator.or_)
258 __ror__ = __or__
259
261 return self._o2(other, operator.xor)
262 __rxor__ = __xor__
263
264
266 return Vec2d(operator.neg(self.x), operator.neg(self.y))
267
269 return Vec2d(operator.pos(self.x), operator.pos(self.y))
270
272 return Vec2d(abs(self.x), abs(self.y))
273
276
277
279 return self.x**2 + self.y**2
280
282 return math.sqrt(self.x**2 + self.y**2)
287 length = property(get_length, __setlength, None, "gets or sets the magnitude of the vector")
288
289 - def rotate(self, angle_degrees):
297
305
311 self.x = self.length
312 self.y = 0
313 self.rotate(angle_degrees)
314 angle = property(get_angle, __setangle, None, "gets or sets the angle of a vector")
315
317 cross = self.x*other[1] - self.y*other[0]
318 dot = self.x*other[0] + self.y*other[1]
319 return math.degrees(math.atan2(cross, dot))
320
326
333
336
342
343 - def dot(self, other):
344 return float(self.x*other[0] + self.y*other[1])
345
347 return math.sqrt((self.x - other[0])**2 + (self.y - other[1])**2)
348
350 return (self.x - other[0])**2 + (self.y - other[1])**2
351
353 other_length_sqrd = other[0]*other[0] + other[1]*other[1]
354 projected_length_times_other_length = self.dot(other)
355 return other*(projected_length_times_other_length/other_length_sqrd)
356
358 return self.x*other[1] - self.y*other[0]
359
361 return Vec2d(self.x + (other[0] - self.x)*range, self.y + (other[1] - self.y)*range)
362
365
367 return [self.x, self.y]
368
370 self.x, self.y = dict
371
372
373
374
375 if __name__ == "__main__":
376
377 import unittest
378 import pickle
379
380
382
385
387 v = Vec2d(111,222)
388 self.assert_(v.x == 111 and v.y == 222)
389 v.x = 333
390 v[1] = 444
391 self.assert_(v[0] == 333 and v[1] == 444)
392
394 v = Vec2d(111,222)
395 self.assertEqual(v + 1, Vec2d(112,223))
396 self.assert_(v - 2 == [109,220])
397 self.assert_(v * 3 == (333,666))
398 self.assert_(v / 2.0 == Vec2d(55.5, 111))
399 self.assert_(v / 2 == (55.5, 111))
400 self.assert_(v ** Vec2d(2,3) == [12321, 10941048])
401 self.assert_(v + [-11, 78] == Vec2d(100, 300))
402 self.assert_(v / [10,2] == [11.1,111])
403
405 v = Vec2d(111,222)
406 self.assert_(1 + v == Vec2d(112,223))
407 self.assert_(2 - v == [-109,-220])
408 self.assert_(3 * v == (333,666))
409 self.assert_([222,888] / v == [2,4])
410 self.assert_([111,222] ** Vec2d(2,3) == [12321, 10941048])
411 self.assert_([-11, 78] + v == Vec2d(100, 300))
412
414 v = Vec2d(111,222)
415 v = -v
416 self.assert_(v == [-111,-222])
417 v = abs(v)
418 self.assert_(v == [111,222])
419
430
432 v = Vec2d(0, 3)
433 self.assertEquals(v.angle, 90)
434 v2 = Vec2d(v)
435 v.rotate(-90)
436 self.assertEqual(v.get_angle_between(v2), 90)
437 v2.angle -= 90
438 self.assertEqual(v.length, v2.length)
439 self.assertEquals(v2.angle, 0)
440 self.assertEqual(v2, [3, 0])
441 self.assert_((v - v2).length < .00001)
442 self.assertEqual(v.length, v2.length)
443 v2.rotate(300)
444 self.assertAlmostEquals(v.get_angle_between(v2), -60)
445 v2.rotate(v2.get_angle_between(v))
446 angle = v.get_angle_between(v2)
447 self.assertAlmostEquals(v.get_angle_between(v2), 0)
448
450 basis0 = Vec2d(5.0, 0)
451 basis1 = Vec2d(0, .5)
452 v = Vec2d(10, 1)
453 self.assert_(v.convert_to_basis(basis0, basis1) == [2, 2])
454 self.assert_(v.projection(basis0) == (10, 0))
455 self.assert_(basis0.dot(basis1) == 0)
456
458 lhs = Vec2d(1, .5)
459 rhs = Vec2d(4,6)
460 self.assert_(lhs.cross(rhs) == 4)
461
463 int_vec = Vec2d(3, -2)
464 flt_vec = Vec2d(3.0, -2.0)
465 zero_vec = Vec2d(0, 0)
466 self.assert_(int_vec == flt_vec)
467 self.assert_(int_vec != zero_vec)
468 self.assert_((flt_vec == zero_vec) == False)
469 self.assert_((flt_vec != int_vec) == False)
470 self.assert_(int_vec == (3, -2))
471 self.assert_(int_vec != [0, 0])
472 self.assert_(int_vec != 5)
473 self.assert_(int_vec != [3, -2, -5])
474
476 inplace_vec = Vec2d(5, 13)
477 inplace_ref = inplace_vec
478 inplace_src = Vec2d(inplace_vec)
479 inplace_vec *= .5
480 inplace_vec += .5
481 inplace_vec /= (3, 6)
482 inplace_vec += Vec2d(-1, -1)
483 self.assertEquals(inplace_vec, inplace_ref)
484
486 testvec = Vec2d(5, .3)
487 testvec_str = pickle.dumps(testvec)
488 loaded_vec = pickle.loads(testvec_str)
489 self.assertEquals(testvec, loaded_vec)
490
491
492 unittest.main()
493
494
495