import numpy as np import itertools as it from PIL import Image from colour import Color from random import random import string import re import operator as op from constants import * def digest_config(obj, Class, kwargs, local_args = {}): """ To be used in initializing most-to-all objects. Sets key word args as local variables """ if hasattr(Class, "DEFAULT_CONFIG"): config = Class.DEFAULT_CONFIG.copy() else: config = {} for key in config.keys(): if hasattr(obj, key): config.pop(key) if key in kwargs: config[key] = kwargs.pop(key) for key in local_args: if key not in ["self", "kwargs"]: config[key] = local_args[key] obj.__dict__.update(config) def interpolate(start, end, alpha): return (1-alpha)*start + alpha*end def center_of_mass(points): points = [np.array(point).astype("float") for point in points] return sum(points) / len(points) def choose(n, r): if n < r: return 0 if r == 0: return 1 denom = reduce(op.mul, xrange(1, r+1), 1) numer = reduce(op.mul, xrange(n, n-r, -1), 1) return numer//denom def is_on_line(p0, p1, p2, threshold = 0.01): """ Returns true of p0 is on the line between p1 and p2 """ p0, p1, p2 = map(lambda tup : np.array(tup[:2]), [p0, p1, p2]) p1 -= p0 p2 -= p0 return abs((p1[0] / p1[1]) - (p2[0] / p2[1])) < threshold def intersection(line1, line2): """ A "line" should come in the form [(x0, y0), (x1, y1)] for two points it runs through """ p0, p1, p2, p3 = map( lambda tup : np.array(tup[:2]), [line1[0], line1[1], line2[0], line2[1]] ) p1, p2, p3 = map(lambda x : x - p0, [p1, p2, p3]) transform = np.zeros((2, 2)) transform[:,0], transform[:,1] = p1, p2 if np.linalg.det(transform) == 0: return inv = np.linalg.inv(transform) new_p3 = np.dot(inv, p3.reshape((2, 1))) #Where does line connecting (0, 1) to new_p3 hit x axis x_intercept = new_p3[0] / (1 - new_p3[1]) result = np.dot(transform, [[x_intercept], [0]]) result = result.reshape((2,)) + p0 return result def random_color(): color = Color() color.set_rgb([1 - 0.5 * random() for x in range(3)]) return color ################################################ def to_cammel_case(name): return "".join([ filter( lambda c : c not in string.punctuation + string.whitespace, part ).capitalize() for part in name.split("_") ]) def initials(name, sep_values = [" ", "_"]): return "".join([ (s[0] if s else "") for s in re.split("|".join(sep_values), name) ]) def cammel_case_initials(name): return filter(lambda c : c.isupper(), name) ################################################ def drag_pixels(frames): curr = frames[0] new_frames = [] for frame in frames: curr += (curr == 0) * np.array(frame) new_frames.append(np.array(curr)) return new_frames def invert_image(image): arr = np.array(image) arr = (255 * np.ones(arr.shape)).astype(arr.dtype) - arr return Image.fromarray(arr) def make_even(iterable_1, iterable_2): list_1, list_2 = list(iterable_1), list(iterable_2) length = max(len(list_1), len(list_2)) return ( [list_1[(n * len(list_1)) / length] for n in xrange(length)], [list_2[(n * len(list_2)) / length] for n in xrange(length)] ) def make_even_by_cycling(iterable_1, iterable_2): length = max(len(iterable_1), len(iterable_2)) cycle1 = it.cycle(iterable_1) cycle2 = it.cycle(iterable_2) return ( [cycle1.next() for x in range(length)], [cycle2.next() for x in range(length)] ) ### Alpha Functions ### def sigmoid(x): return 1.0/(1 + np.exp(-x)) def smooth(t, inflection = 10.0): error = sigmoid(-inflection / 2) return (sigmoid(inflection*(t - 0.5)) - error) / (1 - 2*error) def rush_into(t): return 2*smooth(t/2.0) def rush_from(t): return 2*smooth(t/2.0+0.5) - 1 def slow_into(t): return np.sqrt(1-(1-t)*(1-t)) def there_and_back(t, inflection = 10.0): new_t = 2*t if t < 0.5 else 2*(1 - t) return smooth(new_t, inflection) def not_quite_there(t, proportion = 0.7): return proportion*smooth(t) def wiggle(t, wiggles = 2): return there_and_back(t) * np.sin(wiggles*np.pi*t) def squish_alpha_func(func, a = 0.4, b = 0.6): def result(t): if t < a: return func(0) elif t > b: return func(1) else: return func((t-a)/(b-a)) return result ### Functional Functions ### def composition(func_list): """ func_list should contain elements of the form (f, args) """ return reduce( lambda (f1, args1), (f2, args2) : (lambda x : f1(f2(x, *args2), *args1)), func_list, lambda x : x ) def remove_nones(sequence): return filter(lambda x : x, sequence) #Matrix operations def thick_diagonal(dim, thickness = 2): row_indices = np.arange(dim).repeat(dim).reshape((dim, dim)) col_indices = np.transpose(row_indices) return (np.abs(row_indices - col_indices)