Source code for butterfly.vectormath

"""Calculate anitclockwise angle between two vectors."""
import math

__all__ = ('angle_anitclockwise', 'cross_product', 'project')


def length(v):
    """calculate length of vector."""
    if len(v) == 2:
        v = (v[0], v[1], 0)

    return math.sqrt(v[0] ** 2 + v[1] ** 2 + v[2] ** 2)


def dot_product(v, w):
    """calcualte dot product."""
    if len(v) == 2:
        v = (v[0], v[1], 0)
    if len(w) == 2:
        w = (w[0], w[1], 0)

    return v[0] * w[0] + v[1] * w[1] + v[2] * w[2]


def determinant(v, w):
    """determinant."""
    return v[0] * w[1] - v[1] * w[0]


def inner_angle(v, w):
    """calculate inner angle between two vectors.

    modified from: http://stackoverflow.com/a/31735880
    """
    cosx = dot_product(v, w) / (length(v) * length(w))
    rad = math.acos(cosx)  # in radians
    return rad * 180 / math.pi  # returns degrees


[docs]def angle_anitclockwise(v1, v2): """Calculate clockwise angle between two 2D vectors.""" v1 = v1[:2] v2 = v2[:2] inner = inner_angle(v1, v2) det = determinant(v1, v2) if inner % 360 == 0: return 0 if det > 0: # if the det > 0 then A is immediately clockwise of B return inner else: # this is a property of the det. If the det < 0 then B is clockwise of A return 360 - inner
[docs]def cross_product(v1, v2, norm=True): """Calculate cross product of two 3d vector.""" # handle 2D vectors v1 = (v1[0], v1[1], 0) if len(v1) == 2 else v1 v2 = (v2[0], v2[1], 0) if len(v2) == 2 else v2 v = (v1[1] * v2[2] - v1[2] * v2[1], -v1[0] * v2[2] + v1[2] * v2[0], v1[0] * v2[1] - v1[1] * v2[0]) if norm: return normalize(v) else: return v
def normalize(v): """Normalize a vector.""" ln = length(v) if ln == 0: raise ValueError('A vector with length of 0 cannot be normalized.') return tuple(c / ln for c in v) def move(p, v): """move a point along a vector and return a new pt.""" return tuple(i + j for i, j in zip(p, v)) def scale(v, s): """Scale b by s.""" return tuple(i * s for i in v) def sums(vectors): """Add up a number of vectors.""" return tuple(sum(v) for v in zip(*vectors)) def rotate(origin, point, angle): u"""Rotate a point anitclockwise by a given angle around a given origin. The angle should be given in degrees. modified from: http://stackoverflow.com/a/34374437/4394669 """ angle = math.radians(angle) ox, oy, oz = origin px, py, pz = point cosine = math.cos(angle) sine = math.sin(angle) qx = ox + cosine * (px - ox) - sine * (py - oy) qy = oy + sine * (px - ox) + cosine * (py - oy) return qx, qy, pz def subtract(v1, v2): """subtract v2 from v1.""" return tuple(a - b for a, b in zip(v1, v2))
[docs]def project(p, o, n): """Project a point3d on a plane. Args: p: Point. o: Origin of plane. n: Plane normal. Returns: projected point as (x, y, z) """ n = normalize(n) dif = scale(n, dot_product(subtract(p, o), n)) return subtract(p, dif)