Version

Quick search

Table Of Contents

Source code for kivy.vector

'''Vector
======

The :class:`Vector` represents a 2D vector (x, y).
Our implementation is built on top of a Python list.

 An example of constructing a Vector::

    >>> # Construct a point at 82,34
    >>> v = Vector(82, 34)
    >>> v[0]
    82
    >>> v.x
    82
    >>> v[1]
    34
    >>> v.y
    34

    >>> # Construct by giving a list of 2 values
    >>> pos = (93, 45)
    >>> v = Vector(pos)
    >>> v[0]
    93
    >>> v.x
    93
    >>> v[1]
    45
    >>> v.y
    45


Optimized usage
---------------

Most of the time, you can use a list for arguments instead of using a
Vector. For example, if you want to calculate the distance between 2
points::

    a = (10, 10)
    b = (87, 34)

    # optimized method
    print('distance between a and b:', Vector(a).distance(b))

    # non-optimized method
    va = Vector(a)
    vb = Vector(b)
    print('distance between a and b:', va.distance(vb))


Vector operators
----------------

The :class:`Vector` supports some numeric operators such as +, -, /::

    >>> Vector(1, 1) + Vector(9, 5)
    [10, 6]

    >>> Vector(9, 5) - Vector(5, 5)
    [4, 0]

    >>> Vector(10, 10) / Vector(2., 4.)
    [5.0, 2.5]

    >>> Vector(10, 10) / 5.
    [2.0, 2.0]


You can also use in-place operators::

    >>> v = Vector(1, 1)
    >>> v += 2
    >>> v
    [3, 3]
    >>> v *= 5
    [15, 15]
    >>> v /= 2.
    [7.5, 7.5]

'''

__all__ = ('Vector', )

import math


[docs]class Vector(list): '''Vector class. See module documentation for more information. ''' def __init__(self, *largs): if len(largs) == 1: super(Vector, self).__init__(largs[0]) elif len(largs) == 2: super(Vector, self).__init__(largs) else: raise Exception('Invalid vector') def _get_x(self): return self[0] def _set_x(self, x): self[0] = x x = property(_get_x, _set_x) ''':attr:`x` represents the first element in the list. >>> v = Vector(12, 23) >>> v[0] 12 >>> v.x 12 ''' def _get_y(self): return self[1] def _set_y(self, y): self[1] = y y = property(_get_y, _set_y) ''':attr:`y` represents the second element in the list. >>> v = Vector(12, 23) >>> v[1] 23 >>> v.y 23 ''' def __getslice__(self, i, j): try: # use the list __getslice__ method and convert # result to vector return Vector(super(Vector, self).__getslice__(i, j)) except Exception: raise TypeError('vector::FAILURE in __getslice__') def __add__(self, val): return Vector(list(map(lambda x, y: x + y, self, val))) def __iadd__(self, val): if type(val) in (int, float): self.x += val self.y += val else: self.x += val.x self.y += val.y return self def __neg__(self): return Vector([-x for x in self]) def __sub__(self, val): return Vector(list(map(lambda x, y: x - y, self, val))) def __isub__(self, val): if type(val) in (int, float): self.x -= val self.y -= val else: self.x -= val.x self.y -= val.y return self def __mul__(self, val): try: return Vector(list(map(lambda x, y: x * y, self, val))) except Exception: return Vector([x * val for x in self]) def __imul__(self, val): if type(val) in (int, float): self.x *= val self.y *= val else: self.x *= val.x self.y *= val.y return self def __rmul__(self, val): return (self * val) def __truediv__(self, val): try: return Vector(list(map(lambda x, y: x / y, self, val))) except Exception: return Vector([x / val for x in self]) def __div__(self, val): try: return Vector(list(map(lambda x, y: x / y, self, val))) except Exception: return Vector([x / val for x in self]) def __rtruediv__(self, val): try: return Vector(*val) / self except Exception: return Vector(val, val) / self def __rdiv__(self, val): try: return Vector(*val) / self except Exception: return Vector(val, val) / self def __idiv__(self, val): if type(val) in (int, float): self.x /= val self.y /= val else: self.x /= val.x self.y /= val.y return self
[docs] def length(self): '''Returns the length of a vector. >>> Vector(10, 10).length() 14.142135623730951 >>> pos = (10, 10) >>> Vector(pos).length() 14.142135623730951 ''' return math.sqrt(self[0] ** 2 + self[1] ** 2)
[docs] def length2(self): '''Returns the length of a vector squared. >>> Vector(10, 10).length2() 200 >>> pos = (10, 10) >>> Vector(pos).length2() 200 ''' return self[0] ** 2 + self[1] ** 2
[docs] def distance(self, to): '''Returns the distance between two points. >>> Vector(10, 10).distance((5, 10)) 5. >>> a = (90, 33) >>> b = (76, 34) >>> Vector(a).distance(b) 14.035668847618199 ''' return math.sqrt((self[0] - to[0]) ** 2 + (self[1] - to[1]) ** 2)
[docs] def distance2(self, to): '''Returns the distance between two points squared. >>> Vector(10, 10).distance2((5, 10)) 25 ''' return (self[0] - to[0]) ** 2 + (self[1] - to[1]) ** 2
[docs] def normalize(self): '''Returns a new vector that has the same direction as vec, but has a length of one. >>> v = Vector(88, 33).normalize() >>> v [0.93632917756904444, 0.3511234415883917] >>> v.length() 1.0 ''' if self[0] == 0. and self[1] == 0.: return Vector(0., 0.) return self / self.length()
[docs] def dot(self, a): '''Computes the dot product of a and b. >>> Vector(2, 4).dot((2, 2)) 12 ''' return self[0] * a[0] + self[1] * a[1]
[docs] def angle(self, a): '''Computes the angle between a and b, and returns the angle in degrees. >>> Vector(100, 0).angle((0, 100)) -90.0 >>> Vector(87, 23).angle((-77, 10)) -157.7920283010705 ''' angle = -(180 / math.pi) * math.atan2( self[0] * a[1] - self[1] * a[0], self[0] * a[0] + self[1] * a[1]) return angle
[docs] def rotate(self, angle): '''Rotate the vector with an angle in degrees. >>> v = Vector(100, 0) >>> v.rotate(45) >>> v [70.710678118654755, 70.710678118654741] ''' angle = math.radians(angle) return Vector( (self[0] * math.cos(angle)) - (self[1] * math.sin(angle)), (self[1] * math.cos(angle)) + (self[0] * math.sin(angle)))
[docs] @staticmethod def line_intersection(v1, v2, v3, v4): ''' Finds the intersection point between the lines (1)v1->v2 and (2)v3->v4 and returns it as a vector object. >>> a = (98, 28) >>> b = (72, 33) >>> c = (10, -5) >>> d = (20, 88) >>> Vector.line_intersection(a, b, c, d) [15.25931928687196, 43.911669367909241] .. warning:: This is a line intersection method, not a segment intersection. For math see: http://en.wikipedia.org/wiki/Line-line_intersection ''' # linear algebar sucks...seriously!! x1, x2, x3, x4 = float(v1[0]), float(v2[0]), float(v3[0]), float(v4[0]) y1, y2, y3, y4 = float(v1[1]), float(v2[1]), float(v3[1]), float(v4[1]) u = (x1 * y2 - y1 * x2) v = (x3 * y4 - y3 * x4) denom = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4) if denom == 0: return None px = (u * (x3 - x4) - (x1 - x2) * v) / denom py = (u * (y3 - y4) - (y1 - y2) * v) / denom return Vector(px, py)
[docs] @staticmethod def segment_intersection(v1, v2, v3, v4): ''' Finds the intersection point between segments (1)v1->v2 and (2)v3->v4 and returns it as a vector object. >>> a = (98, 28) >>> b = (72, 33) >>> c = (10, -5) >>> d = (20, 88) >>> Vector.segment_intersection(a, b, c, d) None >>> a = (0, 0) >>> b = (10, 10) >>> c = (0, 10) >>> d = (10, 0) >>> Vector.segment_intersection(a, b, c, d) [5, 5] ''' # Yaaay! I love linear algebra applied within the realms of geometry. x1, x2, x3, x4 = float(v1[0]), float(v2[0]), float(v3[0]), float(v4[0]) y1, y2, y3, y4 = float(v1[1]), float(v2[1]), float(v3[1]), float(v4[1]) # This is mostly the same as the line_intersection u = (x1 * y2 - y1 * x2) v = (x3 * y4 - y3 * x4) denom = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4) if denom == 0: return None px = (u * (x3 - x4) - (x1 - x2) * v) / denom py = (u * (y3 - y4) - (y1 - y2) * v) / denom # Here are the new bits c1 = (x1 <= px <= x2) or (x2 <= px <= x1) or (x1 == x2) c2 = (y1 <= py <= y2) or (y2 <= py <= y1) or (y1 == y2) c3 = (x3 <= px <= x4) or (x4 <= px <= x3) or (x3 == x4) c4 = (y3 <= py <= y4) or (y4 <= py <= y3) or (y3 == y4) if (c1 and c2) and (c3 and c4): return Vector(px, py) else: return None
[docs] @staticmethod def in_bbox(point, a, b): '''Return True if `point` is in the bounding box defined by `a` and `b`. >>> bmin = (0, 0) >>> bmax = (100, 100) >>> Vector.in_bbox((50, 50), bmin, bmax) True >>> Vector.in_bbox((647, -10), bmin, bmax) False ''' return ((point[0] <= a[0] and point[0] >= b[0] or point[0] <= b[0] and point[0] >= a[0]) and (point[1] <= a[1] and point[1] >= b[1] or point[1] <= b[1] and point[1] >= a[1]))