Beginning Hilbert project

This commit is contained in:
Grant Sanderson 2015-11-23 10:34:42 -08:00
parent 199c600e36
commit 591515133b
13 changed files with 244 additions and 55 deletions

View file

@ -1,13 +1 @@
from animation import *
from scene import *
from topics import *
from constants import *
from displayer import *
from extract_scene import *
from helpers import *
from image_mobject import *
from mobject import *
from old_proje import *
from playground import *
from region import *
from tex_utils import *

View file

@ -1,4 +1,8 @@
from animation import *
from meta_animations import *
from simple_animations import *
from transform import *
__all__ = [
"animation",
"meta_animations",
"simple_animations",
"transform"
]
from animation import Animation

View file

@ -8,7 +8,7 @@ import progressbar
import inspect
from helpers import *
from mobject import Mobject, Point
from mobject import Mobject
class Animation(object):
DEFAULT_CONFIG = {

View file

@ -7,7 +7,8 @@ import warnings
from helpers import *
from animation import Animation
from mobject import Mobject, Point
from mobject import Mobject
from topics.geometry import Point
class Transform(Animation):
DEFAULT_CONFIG = {

View file

@ -30,7 +30,7 @@ DEFAULT_POINT_DENSITY_1D = 200
DEFAULT_POINT_THICKNESS = 6
#TODO, Make sure these are not needd
#TODO, Make sure these are not needed
SPACE_HEIGHT = 4.0
SPACE_WIDTH = SPACE_HEIGHT * DEFAULT_WIDTH / DEFAULT_HEIGHT

View file

@ -137,6 +137,9 @@ def prompt_user_for_choice(name_to_obj):
sys.exit()
def get_scene_args(SceneClass, config):
"""
Return arguments as a sequence
"""
tuplify = lambda x : x if type(x) == tuple else (x,)
args_list = map(tuplify, SceneClass.args_list)
preset_extensions = [
@ -192,7 +195,7 @@ def main():
scene_kwargs["announce_construction"] = True
for SceneClass in get_scene_classes(scene_names_to_classes, config):
for args in get_scene_args(SceneClass, config):
scene_kwargs["construct_args"] = args
scene_kwargs["construct_args"] = tuplify(args)
try:
handle_scene(SceneClass(**scene_kwargs), **config)
except:

View file

@ -3,7 +3,7 @@ import itertools as it
import operator as op
from PIL import Image
from colour import Color
from random import random
import random
import inspect
import string
import re
@ -11,6 +11,14 @@ import re
from constants import *
def bezier(points):
n = len(points) - 1
return lambda t : sum([
((1-t)**(n-k))*(t**k)*choose(n, k)*point
for point, k in zip(points, it.count())
])
def remove_list_redundancies(l):
"""
Used instead of lsit(set(l)) to maintain order
@ -33,6 +41,12 @@ def adjascent_pairs(objects):
def complex_to_R3(complex_num):
return np.array((complex_num.real, complex_num.imag, 0))
def tuplify(obj):
try:
return tuple(obj)
except:
return (obj,)
def instantiate(obj):
"""
Useful so that classes or instance of those classes can be
@ -120,9 +134,7 @@ def intersection(line1, line2):
return result
def random_color():
color = Color()
color.set_rgb([1 - 0.5 * random() for x in range(3)])
return color
return random.choice(PALETTE)
################################################
@ -314,7 +326,7 @@ def z_to_vector(vector):
])
return np.dot(rotation_about_z(theta), phi_down)
def rotate_vector(vector, angle, axis):
def rotate_vector(vector, angle, axis = OUT):
return np.dot(rotation_matrix(angle, axis), vector)
def angle_between(v1, v2):

155
hilbert.py Normal file
View file

@ -0,0 +1,155 @@
from mobject import Mobject, Mobject1D
from scene import Scene
from animation.transform import Transform
from animation.simple_animations import ShowCreation
from topics.geometry import Line, Point
from helpers import *
def flip_over_slope_1(points):
return points[:,[1, 0 , 2]]
def flip_over_slope_neg_1(points):
return -points[:,[1, 0, 2]]
def hilbertification(points, radius=3):
transformed_copies = [
flip(points/2) + offset*radius/2.0
for flip, offset in [
(flip_over_slope_1, (LEFT+DOWN)),
(lambda x : x, (LEFT+UP)),
(lambda x : x, (RIGHT+UP)),
(flip_over_slope_neg_1, (RIGHT+DOWN)),
]
]
return reduce(
lambda a, b : np.append(a, b, axis = 0),
transformed_copies
)
class SpaceFillingCurve(Mobject1D):
DEFAULT_CONFIG = {
"radius" : 3,
"order" : 5,
"start_color" : RED,
"end_color" : GREEN,
}
def generate_points(self):
points = self.get_anchor_points(self.order)
for pair in zip(points, points[1:]):
self.add_line(*pair, min_density = 0.01)
self.gradient_highlight(self.start_color, self.end_color)
def get_anchor_points(self, order):
"""
To be filled out in subclasses
"""
return []
class HilbertCurve(SpaceFillingCurve):
def get_anchor_points(self, order):
points = np.zeros((1, 3))
for count in range(order):
points = hilbertification(points)
return points
class HilbertCurve3D(SpaceFillingCurve):
def get_anchor_points(self, order):
pass
class SnakeCurve(SpaceFillingCurve):
DEFAULT_CONFIG = {
"start_color" : BLUE,
"end_color" : YELLOW,
}
def get_anchor_points(self, order):
result = []
lower_left = ORIGIN + \
LEFT*self.radius + \
DOWN*self.radius
step = 2.0*self.radius / (order)
for y in range(order+1):
x_range = range(order+1)
if y%2 == 0:
x_range.reverse()
for x in x_range:
result.append(
lower_left + x*step*RIGHT + y*step*UP
)
return result
class SpaceFillingCurveScene(Scene):
DEFAULT_CONFIG = {
"curve_class" : None #Must be filled in in subclasses
}
@staticmethod
def args_to_string(max_order):
return str(max_order)
@staticmethod
def string_to_args(num_str):
return int(num_str)
class SpaceFillingCurveGrowingOrder(SpaceFillingCurveScene):
def construct(self, max_order):
sample = self.curve_class(order = 1)
curve = Line(sample.radius*LEFT, sample.radius*RIGHT)
curve.gradient_highlight(
sample.start_color,
sample.end_color
)
for order in range(1, max_order):
new_curve = self.curve_class(order = order)
self.play(
Transform(curve, new_curve),
run_time = 3/np.sqrt(order),
)
self.dither()
class HilbertCurveGrowingOrder(SpaceFillingCurveGrowingOrder):
DEFAULT_CONFIG = {
"curve_class" : HilbertCurve,
}
class SnakeCurveGrowingOrder(SpaceFillingCurveGrowingOrder):
DEFAULT_CONFIG = {
"curve_class" : SnakeCurve,
}
class DrawSpaceFillingCurve(SpaceFillingCurveScene):
def construct(self, order):
curve = self.curve_class(order = order)
self.play(ShowCreation(curve), run_time = 10)
self.dither()
class DrawHilbertCurve(DrawSpaceFillingCurve):
DEFAULT_CONFIG = {
"curve_class" : HilbertCurve,
}
class DrawSnakeCurve(DrawSpaceFillingCurve):
DEFAULT_CONFIG = {
"curve_class" : SnakeCurve,
}

View file

@ -1,3 +1,7 @@
from mobject import *
from image_mobject import *
from tex_mobject import *
__all__ = [
"mobject",
"image_mobject",
"tex_mobject",
]
from mobject import Mobject, Mobject1D, Mobject2D

View file

@ -6,7 +6,6 @@ from PIL import Image
from random import random
from copy import deepcopy
from colour import Color
import inspect
import displayer as disp
from helpers import *
@ -168,6 +167,19 @@ class Mobject(object):
mob.rgbs[:,:] = rgb
return self
def gradient_highlight(self, start_color, end_color):
start_rgb, end_rgb = [
np.array(Color(color).get_rgb())
for color in start_color, end_color
]
for mob in self.get_full_submobject_family():
num_points = len(mob.points)
mob.rgbs = np.array([
interpolate(start_rgb, end_rgb, alpha)
for alpha in np.arange(num_points)/float(num_points)
])
return self
def filter_out(self, condition):
for mob in self.get_full_submobject_family():
if len(mob.points) == 0:
@ -329,9 +341,14 @@ class Mobject(object):
def get_all_points(self):
return self.get_merged_array("points")
def get_all_rgbs(self):
return self.get_merged_array("rgbs")
def ingest_sub_mobjects(self):
for attr in self.get_array_attrs():
setattr(self, attr, self.get_merged_array(attr))
attrs = self.get_array_attrs()
arrays = map(self.get_merged_array, attrs)
for attr, array in zip(attrs, arrays):
setattr(self, attr, array)
self.sub_mobjects = []
return self
@ -460,7 +477,7 @@ class Mobject(object):
getattr(mobject2, attr),
alpha))
#TODO, Make the two implementations bellow not redundant
#TODO, Make the two implementations bellow non-redundant
class Mobject1D(Mobject):
DEFAULT_CONFIG = {
"density" : DEFAULT_POINT_DENSITY_1D,
@ -489,18 +506,6 @@ class Mobject2D(Mobject):
Mobject.__init__(self, **kwargs)
class Point(Mobject):
DEFAULT_CONFIG = {
"color" : BLACK,
}
def __init__(self, location = ORIGIN, **kwargs):
digest_locals(self)
Mobject.__init__(self, **kwargs)
def generate_points(self):
self.add_points([self.location])

View file

@ -1 +1,5 @@
from scene import *
__all__ = [
"scene"
]
from scene import Scene

View file

@ -1,9 +1,11 @@
from arithmetic import *
from characters import *
from combinatorics import *
from complex_numbers import *
from functions import *
from geometry import *
from graph_theory import *
from number_line import *
from three_dimensions import *
__all__ = [
"arithmetic",
"characters",
"combinatorics",
"complex_numbers",
"functions",
"geometry",
"graph_theory",
"number_line",
"three_dimensions",
]

View file

@ -3,6 +3,17 @@ from helpers import *
from mobject import Mobject, Mobject1D
class Point(Mobject):
DEFAULT_CONFIG = {
"color" : BLACK,
}
def __init__(self, location = ORIGIN, **kwargs):
digest_locals(self)
Mobject.__init__(self, **kwargs)
def generate_points(self):
self.add_points([self.location])
class Dot(Mobject1D): #Use 1D density, even though 2D
DEFAULT_CONFIG = {
"radius" : 0.05