mirror of
https://github.com/3b1b/manim.git
synced 2025-09-19 04:41:56 +00:00
Beginning Hilbert project
This commit is contained in:
parent
199c600e36
commit
591515133b
13 changed files with 244 additions and 55 deletions
14
__init__.py
14
__init__.py
|
@ -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 *
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
22
helpers.py
22
helpers.py
|
@ -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
155
hilbert.py
Normal 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,
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -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
|
|
@ -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])
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1 +1,5 @@
|
|||
from scene import *
|
||||
__all__ = [
|
||||
"scene"
|
||||
]
|
||||
|
||||
from scene import Scene
|
|
@ -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",
|
||||
]
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue