
"Point/vector arithmetic."

from math import sqrt

class Point(object):
    "A point in 3D space."

    __slots__ = ('px', 'py', 'pz')

    def __init__(self, x, y, z):
        self.px = x
        self.py = y
        self.pz = z

    def __add__(self, vec):
        "Add a vector to this point, returning another point."

        return Point(
            self.px + vec.vx,
            self.py + vec.vy,
            self.pz + vec.vz)

    def __sub__(self, other):
        "Subtract another point from this one, returning a vector."

        return Vector(
            self.px - other.px,
            self.py - other.py,
            self.pz - other.pz)

    def __iter__(self):
        return iter((self.px, self.py, self.pz))

    def __repr__(self):
        return '<Point %r %r %r>' % (self.px, self.py, self.pz)

class Vector(object):
    "A vector in 3D space."

    __slots__ = ('vx', 'vy', 'vz')

    def __init__(self, x, y, z):
        self.vx = x
        self.vy = y
        self.vz = z

    def __iter__(self):
        return iter((self.vx, self.vy, self.vz))

    def __neg__(self):
        return Vector(-self.vx, -self.vy, -self.vz)

    def __add__(self, other):
        return Vector(
            self.vx + other.vx,
            self.vy + other.vy,
            self.vz + other.vz)

    def __mul__(self, n):
        return Vector(self.vx * n, self.vy * n, self.vz * n)

    def __div__(self, n):
        return Vector(self.vx / n, self.vy / n, self.vz / n)

    def length(self):
        "Compute this vector's length."

        return sqrt(self.vx ** 2 + self.vy ** 2 + self.vz ** 2)

    def normalize(self):
        "Convert this vector to a unit vector."

        return self / self.length()

    def __repr__(self):
        return '<Vector %r %r %r>' % (self.vx, self.vy, self.vz)

def cross(a, b):
    "Compute cross product of two vectors."

    return Vector(
        a.vy * b.vz - a.vz * b.vy,
        a.vz * b.vx - a.vx * b.vz,
        a.vx * b.vy - a.vy * b.vx)

def normal(v1, v2, v3):
    "Compute normal given three vectors."

    return cross(v2 - v1, v3 - v2)

