diff --git a/animation/transform.py b/animation/transform.py index 5a977437..baf36fc2 100644 --- a/animation/transform.py +++ b/animation/transform.py @@ -78,12 +78,19 @@ class CounterclockwiseTransform(Transform): "interpolation_function" : counterclockwise_path() } -class SpinInFromNothing(Transform): +class GrowFromCenter(Transform): + def __init__(self, mobject, **kwargs): + Transform.__init__( + self, + Point(mobject.get_center()), + mobject, + **kwargs + ) + +class SpinInFromNothing(GrowFromCenter): DEFAULT_CONFIG = { "interpolation_function" : counterclockwise_path() } - def __init__(self, mob, **kwargs): - Transform.__init__(self, Point(mob.get_center()), mob, **kwargs) class ApplyMethod(Transform): def __init__(self, method, *args, **kwargs): diff --git a/helpers.py b/helpers.py index 9893b518..106aea36 100644 --- a/helpers.py +++ b/helpers.py @@ -170,10 +170,10 @@ def path_along_arc(arc_angle): return path def clockwise_path(): - return path_along_arc(np.pi) + return path_along_arc(-np.pi) def counterclockwise_path(): - return path_along_arc(-np.pi) + return path_along_arc(np.pi) ################################################ diff --git a/hilbert/curves.py b/hilbert/curves.py index f7f92226..fc547fc0 100644 --- a/hilbert/curves.py +++ b/hilbert/curves.py @@ -31,6 +31,7 @@ class SpaceFillingCurve(Mobject1D): def get_anchor_points(self): raise Exception("Not implemented") + class LindenmayerCurve(SpaceFillingCurve): DEFAULT_CONFIG = { "axiom" : "A", @@ -112,6 +113,9 @@ class SelfSimilarSpaceFillingCurve(SpaceFillingCurve): points = self.refine_into_subparts(points) return points + def generate_grid(self): + raise Exception("Not implemented") + class HilbertCurve(SelfSimilarSpaceFillingCurve): diff --git a/hilbert/section1.py b/hilbert/section1.py index 72f5e081..045e5736 100644 --- a/hilbert/section1.py +++ b/hilbert/section1.py @@ -5,13 +5,15 @@ from mobject.image_mobject import ImageMobject from scene import Scene from animation import Animation -from animation.transform import Transform, CounterclockwiseTransform, ApplyMethod +from animation.transform import Transform, CounterclockwiseTransform, \ + ApplyMethod, GrowFromCenter from animation.simple_animations import ShowCreation, ShimmerIn from animation.meta_animations import DelayByOrder, TransformAnimations from animation.playground import VibratingString -from topics.geometry import Line +from topics.geometry import Line, Dot, Arrow from topics.characters import ThoughtBubble +from topics.number_line import UnitInterval from helpers import * @@ -178,10 +180,12 @@ class ImageDataIsTwoDimensional(Scene): class SoundDataIsOneDimensional(Scene): def construct(self): overtones = 5 + floor = 2*DOWN main_string = VibratingString(color = BLUE_D) component_strings = [ VibratingString( num_periods = k+1, + overtones = 2, color = color, center = 2*DOWN + UP*k ) @@ -190,17 +194,53 @@ class SoundDataIsOneDimensional(Scene): Color(BLUE_E).range_to(WHITE, overtones) ) ] + dots = [ + Dot( + string.mobject.get_center(), + color = string.mobject.get_color() + ) + for string in component_strings + ] + + freq_line = UnitInterval() + freq_line.shift(floor) + freq_line.sort_points(np.linalg.norm) + brace = Brace(freq_line, UP) + words = TextMobject("Range of frequency values") + words.next_to(brace, UP) + - self.play(main_string) - self.remove(main_string.mobject) self.play(*[ TransformAnimations( main_string.copy(), - string + string, + run_time = 5 ) for string in component_strings ]) - + self.clear() + self.play(*[ + TransformAnimations( + string, + Animation(dot) + ) + for string, dot in zip(component_strings, dots) + ]) + self.clear() + self.play( + ShowCreation(freq_line), + GrowFromCenter(brace), + ShimmerIn(words), + *[ + Transform( + dot, + dot.copy().scale(2).rotate(-np.pi/2).shift(floor), + interpolation_function = path_along_arc(np.pi/3) + ) + for dot in dots + ] + ) + self.dither(0.5) diff --git a/mobject/mobject.py b/mobject/mobject.py index fcec5c88..3322c545 100644 --- a/mobject/mobject.py +++ b/mobject/mobject.py @@ -500,6 +500,7 @@ class Mobject1D(Mobject): def add_line(self, start, end, color = None): + start, end = map(np.array, [start, end]) length = np.linalg.norm(end - start) if length == 0: points = [start] diff --git a/old_projects/complex_multiplication_article.py b/old_projects/complex_multiplication_article.py index b4076433..4fc796c5 100644 --- a/old_projects/complex_multiplication_article.py +++ b/old_projects/complex_multiplication_article.py @@ -209,7 +209,7 @@ class DrawComplexAngleAndMagnitude(Scene): def add_angle_label(self, number): - arc = PartialCircle( + arc = Arc( np.log(number).imag, radius = 0.2 ) diff --git a/topics/geometry.py b/topics/geometry.py index 77858c0f..e306b812 100644 --- a/topics/geometry.py +++ b/topics/geometry.py @@ -37,7 +37,11 @@ class Cross(Mobject1D): class Line(Mobject1D): + DEFAULT_CONFIG = { + "buffer" : 0 + } def __init__(self, start, end, **kwargs): + digest_config(self, kwargs) self.set_start_and_end(start, end) Mobject1D.__init__(self, **kwargs) @@ -58,6 +62,10 @@ class Line(Mobject1D): else np.array(arg) for arg, unit in zip([start, end], [1, -1]) ] + start_to_end = self.end - self.start + start_to_end /= np.linalg.norm(start_to_end) + self.start += self.buffer*start_to_end + self.end += self.buffer*(-start_to_end) def generate_points(self): self.add_line(self.start, self.end) @@ -75,7 +83,8 @@ class Line(Mobject1D): class Arrow(Line): DEFAULT_CONFIG = { "color" : WHITE, - "tip_length" : 0.25 + "tip_length" : 0.25, + "buffer" : 0.3, } def __init__(self, *args, **kwargs): Line.__init__(self, *args, **kwargs) @@ -127,8 +136,7 @@ class CurvedLine(Line): ]) - -class PartialCircle(Mobject1D): +class Arc(Mobject1D): DEFAULT_CONFIG = { "radius" : 1.0, "start_angle" : 0, @@ -148,12 +156,12 @@ class PartialCircle(Mobject1D): ) ]) -class Circle(PartialCircle): +class Circle(Arc): DEFAULT_CONFIG = { "color" : RED, } def __init__(self, **kwargs): - PartialCircle.__init__(self, angle = 2*np.pi, **kwargs) + Arc.__init__(self, angle = 2*np.pi, **kwargs) class Polygon(Mobject1D): DEFAULT_CONFIG = { @@ -180,12 +188,40 @@ class Polygon(Mobject1D): return self.points[self.indices_of_vertices] -class Rectangle(Mobject1D): + +class Grid(Mobject1D): + DEFAULT_CONFIG = { + "height" : 6.0, + "width" : 6.0, + } + def __init__(self, rows, columns, **kwargs): + digest_config(self, kwargs, locals()) + Mobject1D.__init__(self, **kwargs) + + def generate_points(self): + x_step = self.width / self.columns + y_step = self.height / self.rows + + for x in np.arange(0, self.width+x_step, x_step): + self.add_line( + [x-self.width/2., -self.height/2., 0], + [x-self.width/2., self.height/2., 0], + ) + for y in np.arange(0, self.height+y_step, y_step): + self.add_line( + [-self.width/2., y-self.height/2., 0], + [self.width/2., y-self.height/2., 0] + ) + +class Rectangle(Grid): DEFAULT_CONFIG = { "color" : YELLOW, "height" : 2.0, - "width" : 4.0 + "width" : 4.0, } + def __init__(self, **kwargs): + Grid.__init__(self, 1, 1, **kwargs) + def generate_points(self): wh = [self.width/2.0, self.height/2.0] self.add_points([ @@ -209,4 +245,3 @@ class Square(Rectangle): - diff --git a/topics/number_line.py b/topics/number_line.py index 1f052a22..cc0c79cd 100644 --- a/topics/number_line.py +++ b/topics/number_line.py @@ -1,6 +1,7 @@ from helpers import * -from mobject import Mobject1D, TexMobject +from mobject import Mobject1D +from mobject.tex_mobject import TexMobject from scene import Scene class NumberLine(Mobject1D):