mirror of
https://github.com/3b1b/manim.git
synced 2026-04-26 03:00:23 -04:00
Merge branch 'master' into lighthouse
This commit is contained in:
14
README.md
14
README.md
@@ -32,16 +32,20 @@ This doesn't install freetype, but I don't think it's required for this project
|
||||
## How to Use
|
||||
Try running the following:
|
||||
```sh
|
||||
python extract_scene.py -p example_scenes.py SquareToCircle
|
||||
python extract_scene.py example_scenes.py SquareToCircle -p
|
||||
```
|
||||
|
||||
`-p` gives a preview of an animation, `-w` will write it to a file, and `-s` will show/save the final image in the animation.
|
||||
The -p is for previewing, meaning the the video file will automatically open when it is done rendering.
|
||||
Use -l for a faster rendering at a lower quality.
|
||||
Use -s to skip to the end and just show the final frame.
|
||||
Use -n <number> to skip ahead to the n'th animation of a scene.
|
||||
Use -f to show the file in finder (for osx)
|
||||
|
||||
You will probably want to change the ANIMATIONS_DIR constant to be whatever direction you want video files to output to.
|
||||
You will probably want to change the ANIMATIONS_DIR constant to be whatever directory you want video files to output to.
|
||||
|
||||
Look through the old_projects folder to see the code for previous 3b1b videos.
|
||||
Look through the old_projects folder to see the code for previous 3b1b videos. Note, however, that developments are often made to the library without considering backwards compatibility on those old_projects. To run them with a guarantee that they will work, you will have to go back to the commit which complete that project.
|
||||
|
||||
While developing a scene, the `-s` flag is helpful to just see what things look like at the end without having to generate the full animation. It can also be helpful to put `self.force_skipping()` at the top of the construct method, and `self.revert_to_original_skipping_status()` before the portion of the scene that you want to test, and run with the `-p` flag to just see a preview of one part of the scene.
|
||||
While developing a scene, the `-s` flag is helpful to just see what things look like at the end without having to generate the full animation. It can also be helpful to use the -n flag to skip over some number of animations.
|
||||
|
||||
Scene with `PiCreatures` are somewhat 3b1b specific, so the specific designs for various expressions are not part of the public repo. You should still be able to run them, but they will fall back on using the "plain" expression for the creature.
|
||||
|
||||
|
||||
@@ -539,7 +539,7 @@ class UnmixMixedPaint(Scene):
|
||||
def construct(self):
|
||||
angles = np.arange(4)*np.pi/2
|
||||
quadrants = VGroup(*[
|
||||
Quadrant().rotate(angle).highlight(color)
|
||||
Quadrant().rotate(angle, about_point = ORIGIN).highlight(color)
|
||||
for color, angle in zip(self.colors, angles)
|
||||
])
|
||||
quadrants.add(*it.chain(*[
|
||||
@@ -659,8 +659,10 @@ class FourierMachineScene(Scene):
|
||||
"y_axis_config" : {"unit_size" : 0.8},
|
||||
},
|
||||
"circle_plane_config" : {
|
||||
"x_radius" : 2,
|
||||
"y_radius" : 2,
|
||||
"x_radius" : 2.5,
|
||||
"y_radius" : 2.5,
|
||||
"x_unit_size" : 0.8,
|
||||
"y_unit_size" : 0.8,
|
||||
},
|
||||
"frequency_axes_config" : {
|
||||
"number_line_config" : {
|
||||
@@ -1261,6 +1263,15 @@ class DrawFrequencyPlot(WrapCosineGraphAroundCircle, PiCreatureScene):
|
||||
stroke_width = 6,
|
||||
color = fourier_graph.get_color()
|
||||
)
|
||||
fourier_graph_copy = fourier_graph.copy()
|
||||
max_freq = self.frequency_axes.x_max
|
||||
def update_fourier_graph(fg):
|
||||
freq = self.graph.polarized_mobject.frequency
|
||||
fg.pointwise_become_partial(
|
||||
fourier_graph_copy,
|
||||
0, freq/max_freq
|
||||
)
|
||||
return fg
|
||||
|
||||
self.change_frequency(0.0)
|
||||
self.generate_fourier_dot_transform(fourier_graph)
|
||||
@@ -1275,13 +1286,8 @@ class DrawFrequencyPlot(WrapCosineGraphAroundCircle, PiCreatureScene):
|
||||
fourier_graph.restore()
|
||||
self.change_frequency(
|
||||
freq,
|
||||
added_anims = [ShowCreation(
|
||||
fourier_graph,
|
||||
rate_func = lambda t : interpolate(
|
||||
(freq-1.)/f_max,
|
||||
float(freq)/f_max,
|
||||
smooth(t)
|
||||
),
|
||||
added_anims = [UpdateFromFunc(
|
||||
fourier_graph, update_fourier_graph
|
||||
)],
|
||||
run_time = 5,
|
||||
)
|
||||
@@ -1444,10 +1450,56 @@ class StudentsHorrifiedAtScene(TeacherStudentsScene):
|
||||
|
||||
|
||||
class ShowLinearity(DrawFrequencyPlot):
|
||||
CONFIG = {
|
||||
"lower_signal_frequency" : 2.0,
|
||||
"lower_signal_color" : PINK,
|
||||
}
|
||||
def construct(self):
|
||||
self.setup_all_axes()
|
||||
self.show_lower_frequency_signal()
|
||||
self.play_with_lower_frequency_signal()
|
||||
self.point_out_fourier_spike()
|
||||
self.show_sum_of_signals()
|
||||
self.play_with_sum_signal()
|
||||
self.point_out_two_spikes()
|
||||
|
||||
def setup_all_axes(self):
|
||||
self.add(self.get_time_axes())
|
||||
self.add(self.get_circle_plane())
|
||||
self.add(self.get_frequency_axes())
|
||||
self.remove(self.pi_creature)
|
||||
|
||||
def show_lower_frequency_signal(self):
|
||||
axes = self.time_axes
|
||||
start_graph = self.get_cosine_wave(freq = self.signal_frequency)
|
||||
graph = self.get_cosine_wave(freq = self.lower_signal_frequency)
|
||||
graph.highlight(self.lower_signal_color)
|
||||
start_graph.generate_target()
|
||||
start_graph.target.stretch(
|
||||
|
||||
)
|
||||
|
||||
self.add(start_graph)
|
||||
self.play(ReplacementTransform(
|
||||
start_graph, graph, run_time = 3
|
||||
))
|
||||
self.wait()
|
||||
|
||||
def play_with_lower_frequency_signal(self):
|
||||
pass
|
||||
|
||||
def point_out_fourier_spike(self):
|
||||
pass
|
||||
|
||||
def show_sum_of_signals(self):
|
||||
pass
|
||||
|
||||
def play_with_sum_signal(self):
|
||||
pass
|
||||
|
||||
def point_out_two_spikes(self):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -143,7 +143,13 @@ class ApplyMethod(Transform):
|
||||
"the method you want to animate"
|
||||
)
|
||||
assert(isinstance(method.im_self, Mobject))
|
||||
method_kwargs = kwargs.get("method_kwargs", {})
|
||||
args = list(args) #So that args.pop() works
|
||||
if "method_kwargs" in kwargs:
|
||||
method_kwargs = kwargs["method_kwargs"]
|
||||
elif len(args) > 0 and isinstance(args[-1], dict):
|
||||
method_kwargs = args.pop()
|
||||
else:
|
||||
method_kwargs = {}
|
||||
target = method.im_self.copy()
|
||||
method.im_func(target, *args, **method_kwargs)
|
||||
Transform.__init__(self, method.im_self, target, **kwargs)
|
||||
|
||||
@@ -2089,7 +2089,7 @@ class MusicExample(SampleSpaceScene, PiCreatureScene):
|
||||
notes = VGroup(*[note.copy() for x in range(10)])
|
||||
sine_wave = FunctionGraph(np.sin, x_min = -5, x_max = 5)
|
||||
sine_wave.scale(0.75)
|
||||
sine_wave.rotate(np.pi/6)
|
||||
sine_wave.rotate(np.pi/6, about_point = ORIGIN)
|
||||
sine_wave.shift(
|
||||
notes.get_center() - \
|
||||
sine_wave.point_from_proportion(0)
|
||||
|
||||
@@ -1348,7 +1348,7 @@ class IntroduceTelepathyExample(StatisticsVsEmpathy):
|
||||
vect[1] = 0
|
||||
|
||||
arc = Arc(angle = angle)
|
||||
arc.rotate(-angle/2 + angle_of_vector(vect))
|
||||
arc.rotate(-angle/2 + angle_of_vector(vect), about_point = ORIGIN)
|
||||
arc.scale(3)
|
||||
arcs = VGroup(*[arc.copy() for x in range(n_arcs)])
|
||||
arcs.move_to(pi2.eyes.get_center(), vect)
|
||||
|
||||
@@ -3072,7 +3072,7 @@ class CorrectForDependence(NameBinomial):
|
||||
for value, alt_value, bar in zip(values, alt_values, bars):
|
||||
arrow = arrow_template.copy()
|
||||
if value < alt_value:
|
||||
arrow.rotate(np.pi)
|
||||
arrow.rotate(np.pi, about_point = ORIGIN)
|
||||
arrow.next_to(bar, UP)
|
||||
arrows.add(arrow)
|
||||
|
||||
|
||||
@@ -23,8 +23,13 @@ from mobject.tex_mobject import *
|
||||
|
||||
from mobject.vectorized_mobject import *
|
||||
|
||||
## To watch one of these scenes, run the following:
|
||||
## python extract_scene.py file_name <SceneName> -p
|
||||
# To watch one of these scenes, run the following:
|
||||
# python extract_scene.py file_name <SceneName> -p
|
||||
#
|
||||
# Use the flat -l for a faster rendering at a lower
|
||||
# quality, use -s to skip to the end and just show
|
||||
# the final frame, and use -n <number> to skip ahead
|
||||
# to the n'th animation of a scene.
|
||||
|
||||
|
||||
class SquareToCircle(Scene):
|
||||
|
||||
@@ -138,7 +138,7 @@ class Mobject(object):
|
||||
mob.points += total_vector
|
||||
return self
|
||||
|
||||
def scale(self, scale_factor, about_point = None, about_edge = ORIGIN):
|
||||
def scale(self, scale_factor, **kwargs):
|
||||
"""
|
||||
Default behavior is to scale about the center of the mobject.
|
||||
The argument about_edge can be a vector, indicating which side of
|
||||
@@ -148,48 +148,61 @@ class Mobject(object):
|
||||
Otherwise, if about_point is given a value, scaling is done with
|
||||
respect to that point.
|
||||
"""
|
||||
if about_point is None:
|
||||
about_point = self.get_critical_point(about_edge)
|
||||
self.shift(-about_point)
|
||||
for mob in self.family_members_with_points():
|
||||
mob.points *= scale_factor
|
||||
self.shift(about_point)
|
||||
self.apply_points_function_about_point(
|
||||
lambda points : scale_factor*points, **kwargs
|
||||
)
|
||||
return self
|
||||
|
||||
def rotate_about_origin(self, angle, axis = OUT, axes = []):
|
||||
if len(axes) == 0:
|
||||
axes = [axis]
|
||||
rot_matrix = np.identity(self.dim)
|
||||
for axis in axes:
|
||||
rot_matrix = np.dot(rot_matrix, rotation_matrix(angle, axis))
|
||||
t_rot_matrix = np.transpose(rot_matrix)
|
||||
for mob in self.family_members_with_points():
|
||||
mob.points = np.dot(mob.points, t_rot_matrix)
|
||||
return self.rotate(angle, axis, about_point = ORIGIN)
|
||||
|
||||
def rotate(self, angle, axis = OUT, **kwargs):
|
||||
rot_matrix = rotation_matrix(angle, axis)
|
||||
self.apply_points_function_about_point(
|
||||
lambda points : np.dot(points, rot_matrix.T),
|
||||
**kwargs
|
||||
)
|
||||
return self
|
||||
|
||||
def rotate(self, angle, axis = OUT, axes = [], about_point = None):
|
||||
if about_point is None:
|
||||
self.rotate_about_origin(angle, axis, axes)
|
||||
else:
|
||||
self.do_about_point(about_point, self.rotate, angle, axis, axes)
|
||||
def flip(self, axis = UP, **kwargs):
|
||||
return self.rotate(TAU/2, axis, **kwargs)
|
||||
|
||||
def stretch(self, factor, dim, **kwargs):
|
||||
def func(points):
|
||||
points[:,dim] *= factor
|
||||
return points
|
||||
self.apply_points_function_about_point(func, **kwargs)
|
||||
return self
|
||||
|
||||
def stretch(self, factor, dim):
|
||||
for mob in self.family_members_with_points():
|
||||
mob.points[:,dim] *= factor
|
||||
def apply_function(self, function, **kwargs):
|
||||
#Default to applying matrix about the origin, not mobjects center
|
||||
if len(kwargs) == 0:
|
||||
kwargs["about_point"] = ORIGIN
|
||||
self.apply_points_function_about_point(
|
||||
lambda points : np.apply_along_axis(function, 1, points),
|
||||
**kwargs
|
||||
)
|
||||
return self
|
||||
|
||||
def apply_function(self, function):
|
||||
for mob in self.family_members_with_points():
|
||||
mob.points = np.apply_along_axis(function, 1, mob.points)
|
||||
return self
|
||||
|
||||
def apply_matrix(self, matrix):
|
||||
def apply_matrix(self, matrix, **kwargs):
|
||||
#Default to applying matrix about the origin, not mobjects center
|
||||
if len(kwargs) == 0:
|
||||
kwargs["about_point"] = ORIGIN
|
||||
full_matrix = np.identity(self.dim)
|
||||
matrix = np.array(matrix)
|
||||
for mob in self.family_members_with_points():
|
||||
mob.points = np.dot(mob.points, matrix.T)
|
||||
full_matrix[:matrix.shape[0],:matrix.shape[1]] = matrix
|
||||
self.apply_points_function_about_point(
|
||||
lambda points : np.dot(points, full_matrix.T),
|
||||
**kwargs
|
||||
)
|
||||
return self
|
||||
|
||||
def apply_complex_function(self, function, **kwargs):
|
||||
return self.apply_function(
|
||||
lambda (x, y, z) : complex_to_R3(function(complex(x, y))),
|
||||
**kwargs
|
||||
)
|
||||
|
||||
def wag(self, direction = RIGHT, axis = DOWN, wag_factor = 1.0):
|
||||
for mob in self.family_members_with_points():
|
||||
alphas = np.dot(mob.points, np.transpose(axis))
|
||||
@@ -223,37 +236,35 @@ class Mobject(object):
|
||||
return self
|
||||
|
||||
#### In place operations ######
|
||||
#Note, much of these are now redundant with default behavior of
|
||||
#above methods
|
||||
|
||||
def do_about_point(self, point, method, *args, **kwargs):
|
||||
self.shift(-point)
|
||||
method(*args, **kwargs)
|
||||
self.shift(point)
|
||||
return self
|
||||
|
||||
def do_in_place(self, method, *args, **kwargs):
|
||||
self.do_about_point(self.get_center(), method, *args, **kwargs)
|
||||
def apply_points_function_about_point(self, func, about_point = None, about_edge = ORIGIN):
|
||||
if about_point is None:
|
||||
about_point = self.get_critical_point(about_edge)
|
||||
for mob in self.family_members_with_points():
|
||||
mob.points -= about_point
|
||||
mob.points = func(mob.points)
|
||||
mob.points += about_point
|
||||
return self
|
||||
|
||||
def rotate_in_place(self, angle, axis = OUT, axes = []):
|
||||
self.do_in_place(self.rotate, angle, axis, axes)
|
||||
return self
|
||||
# redundant with default behavior of rotate now.
|
||||
return self.rotate(angle, axis = axis, axes = axes)
|
||||
|
||||
def flip(self, axis = UP):
|
||||
self.rotate_in_place(np.pi, axis)
|
||||
return self
|
||||
|
||||
def scale_in_place(self, scale_factor):
|
||||
def scale_in_place(self, scale_factor, **kwargs):
|
||||
#Redundant with default behavior of scale now.
|
||||
self.do_in_place(self.scale, scale_factor)
|
||||
return self
|
||||
return self.scale(scale_factor, **kwargs)
|
||||
|
||||
def scale_about_point(self, scale_factor, point):
|
||||
self.do_about_point(point, self.scale, scale_factor)
|
||||
#Redundant with default behavior of scale now.
|
||||
return self.scale(scale_factor, about_point = point)
|
||||
|
||||
def pose_at_angle(self, **kwargs):
|
||||
self.rotate(TAU/14, RIGHT+UP, **kwargs)
|
||||
return self
|
||||
|
||||
def pose_at_angle(self):
|
||||
self.rotate_in_place(np.pi / 7, RIGHT+UP)
|
||||
return self
|
||||
#### Positioning methods ####
|
||||
|
||||
def center(self):
|
||||
self.shift(-self.get_center())
|
||||
@@ -338,42 +349,41 @@ class Mobject(object):
|
||||
return False
|
||||
|
||||
def stretch_about_point(self, factor, dim, point):
|
||||
self.do_about_point(point, self.stretch, factor, dim)
|
||||
return self
|
||||
return self.stretch(factor, dim, about_point = point)
|
||||
|
||||
def stretch_in_place(self, factor, dim):
|
||||
self.do_in_place(self.stretch, factor, dim)
|
||||
return self
|
||||
#Now redundant with stretch
|
||||
return self.stretch(factor, dim)
|
||||
|
||||
def rescale_to_fit(self, length, dim, stretch = False):
|
||||
def rescale_to_fit(self, length, dim, stretch = False, **kwargs):
|
||||
old_length = self.length_over_dim(dim)
|
||||
if old_length == 0:
|
||||
return self
|
||||
if stretch:
|
||||
self.stretch_in_place(length/old_length, dim)
|
||||
self.stretch(length/old_length, dim, **kwargs)
|
||||
else:
|
||||
self.scale_in_place(length/old_length)
|
||||
self.scale(length/old_length, **kwargs)
|
||||
return self
|
||||
|
||||
def stretch_to_fit_width(self, width):
|
||||
return self.rescale_to_fit(width, 0, stretch = True)
|
||||
def stretch_to_fit_width(self, width, **kwargs):
|
||||
return self.rescale_to_fit(width, 0, stretch = True, **kwargs)
|
||||
|
||||
def stretch_to_fit_height(self, height):
|
||||
return self.rescale_to_fit(height, 1, stretch = True)
|
||||
def stretch_to_fit_height(self, height, **kwargs):
|
||||
return self.rescale_to_fit(height, 1, stretch = True, **kwargs)
|
||||
|
||||
def scale_to_fit_width(self, width):
|
||||
return self.rescale_to_fit(width, 0, stretch = False)
|
||||
def scale_to_fit_width(self, width, **kwargs):
|
||||
return self.rescale_to_fit(width, 0, stretch = False, **kwargs)
|
||||
|
||||
def scale_to_fit_height(self, height):
|
||||
return self.rescale_to_fit(height, 1, stretch = False)
|
||||
def scale_to_fit_height(self, height, **kwargs):
|
||||
return self.rescale_to_fit(height, 1, stretch = False, **kwargs)
|
||||
|
||||
def scale_to_fit_depth(self, depth):
|
||||
return self.rescale_to_fit(depth, 2, stretch = False)
|
||||
def scale_to_fit_depth(self, depth, **kwargs):
|
||||
return self.rescale_to_fit(depth, 2, stretch = False, **kwargs)
|
||||
|
||||
def space_out_submobjects(self, factor = 1.5, **kwargs):
|
||||
self.scale_in_place(factor)
|
||||
self.scale(factor, **kwargs)
|
||||
for submob in self.submobjects:
|
||||
submob.scale_in_place(1./factor)
|
||||
submob.scale(1./factor)
|
||||
return self
|
||||
|
||||
def move_to(self, point_or_mobject, aligned_edge = ORIGIN):
|
||||
@@ -509,11 +519,7 @@ class Mobject(object):
|
||||
sm1.interpolate(sm1, sm2, 1)
|
||||
return self
|
||||
|
||||
def apply_complex_function(self, function, **kwargs):
|
||||
return self.apply_function(
|
||||
lambda (x, y, z) : complex_to_R3(function(complex(x, y))),
|
||||
**kwargs
|
||||
)
|
||||
##
|
||||
|
||||
def reduce_across_dimension(self, points_func, reduce_func, dim):
|
||||
try:
|
||||
@@ -696,7 +702,6 @@ class Mobject(object):
|
||||
"""
|
||||
raise Exception("Not implemented")
|
||||
|
||||
|
||||
def align_points(self, mobject):
|
||||
count1 = self.get_num_points()
|
||||
count2 = mobject.get_num_points()
|
||||
|
||||
@@ -218,7 +218,7 @@ class VMobjectFromSVGPathstring(VMobject):
|
||||
for command, coord_string in pairs:
|
||||
self.handle_command(command, coord_string)
|
||||
#people treat y-coordinate differently
|
||||
self.rotate(np.pi, RIGHT)
|
||||
self.rotate(np.pi, RIGHT, about_point = ORIGIN)
|
||||
|
||||
def handle_command(self, command, coord_string):
|
||||
isLower = command.islower()
|
||||
|
||||
@@ -211,7 +211,7 @@ class Brace(TexMobject):
|
||||
def __init__(self, mobject, direction = DOWN, **kwargs):
|
||||
digest_config(self, kwargs, locals())
|
||||
angle = -np.arctan2(*direction[:2]) + np.pi
|
||||
mobject.rotate(-angle)
|
||||
mobject.rotate(-angle, about_point = ORIGIN)
|
||||
left = mobject.get_corner(DOWN+LEFT)
|
||||
right = mobject.get_corner(DOWN+RIGHT)
|
||||
target_width = right[0]-left[0]
|
||||
@@ -227,7 +227,7 @@ class Brace(TexMobject):
|
||||
self.stretch_to_fit_width(target_width)
|
||||
self.shift(left - self.get_corner(UP+LEFT) + self.buff*DOWN)
|
||||
for mob in mobject, self:
|
||||
mob.rotate(angle)
|
||||
mob.rotate(angle, about_point = ORIGIN)
|
||||
|
||||
def put_at_tip(self, mob, use_next_to = True, **kwargs):
|
||||
if use_next_to:
|
||||
|
||||
@@ -340,8 +340,9 @@ class Scene(object):
|
||||
|
||||
def compile_play_args_to_animation_list(self, *args):
|
||||
"""
|
||||
Eacn arg can either be an animation, or a mobject method
|
||||
followed by that methods arguments.
|
||||
Each arg can either be an animation, or a mobject method
|
||||
followed by that methods arguments (and potentially follow
|
||||
by a dict of kwargs for that method).
|
||||
|
||||
This animation list is built by going through the args list,
|
||||
and each animation is simply added, but when a mobject method
|
||||
@@ -364,8 +365,15 @@ class Scene(object):
|
||||
#method should already have target then.
|
||||
else:
|
||||
mobject.target = mobject.copy()
|
||||
#
|
||||
if len(state["method_args"]) > 0 and isinstance(state["method_args"][-1], dict):
|
||||
method_kwargs = state["method_args"].pop()
|
||||
else:
|
||||
method_kwargs = {}
|
||||
state["curr_method"].im_func(
|
||||
mobject.target, *state["method_args"]
|
||||
mobject.target,
|
||||
*state["method_args"],
|
||||
**method_kwargs
|
||||
)
|
||||
animations.append(MoveToTarget(mobject))
|
||||
state["last_method"] = state["curr_method"]
|
||||
@@ -482,7 +490,7 @@ class Scene(object):
|
||||
path = os.path.join(self.output_directory, folder)
|
||||
file_name = (name or str(self)) + ".png"
|
||||
return os.path.join(path, file_name)
|
||||
|
||||
|
||||
def save_image(self, name = None, mode = "RGB", dont_update = False):
|
||||
path = self.get_image_file_path(name, dont_update)
|
||||
directory_path = os.path.dirname(path)
|
||||
|
||||
@@ -127,7 +127,7 @@ class DiamondFractal(SelfSimilarFractal):
|
||||
# VGroup(*subparts).rotate(np.pi/4)
|
||||
for part, vect in zip(subparts, compass_directions(start_vect = UP+RIGHT)):
|
||||
part.next_to(ORIGIN, vect, buff = 0)
|
||||
VGroup(*subparts).rotate(np.pi/4)
|
||||
VGroup(*subparts).rotate(np.pi/4, about_point = ORIGIN)
|
||||
|
||||
|
||||
class PentagonalFractal(SelfSimilarFractal):
|
||||
@@ -142,7 +142,7 @@ class PentagonalFractal(SelfSimilarFractal):
|
||||
def arrange_subparts(self, *subparts):
|
||||
for x, part in enumerate(subparts):
|
||||
part.shift(0.95*part.get_height()*UP)
|
||||
part.rotate(2*np.pi*x/5)
|
||||
part.rotate(2*np.pi*x/5, about_point = ORIGIN)
|
||||
|
||||
class PentagonalPiCreatureFractal(PentagonalFractal):
|
||||
def init_colors(self):
|
||||
@@ -163,7 +163,7 @@ class PentagonalPiCreatureFractal(PentagonalFractal):
|
||||
|
||||
def arrange_subparts(self, *subparts):
|
||||
for part in subparts:
|
||||
part.rotate(2*np.pi/5)
|
||||
part.rotate(2*np.pi/5, about_point = ORIGIN)
|
||||
PentagonalFractal.arrange_subparts(self, *subparts)
|
||||
|
||||
|
||||
@@ -236,7 +236,7 @@ class WonkyHexagonFractal(SelfSimilarFractal):
|
||||
|
||||
def arrange_subparts(self, *subparts):
|
||||
for i, piece in enumerate(subparts):
|
||||
piece.rotate(i*np.pi/12)
|
||||
piece.rotate(i*np.pi/12, about_point = ORIGIN)
|
||||
p1, p2, p3, p4, p5, p6, p7 = subparts
|
||||
center_row = VGroup(p1, p4, p7)
|
||||
center_row.arrange_submobjects(RIGHT, buff = 0)
|
||||
@@ -265,7 +265,7 @@ class CircularFractal(SelfSimilarFractal):
|
||||
ORIGIN, UP,
|
||||
buff = self.height/(2*np.tan(theta))
|
||||
)
|
||||
part.rotate(i*2*np.pi/self.num_subparts)
|
||||
part.rotate(i*2*np.pi/self.num_subparts, about_point = ORIGIN)
|
||||
self.num_subparts -= 1
|
||||
|
||||
|
||||
@@ -548,7 +548,7 @@ class FlowSnake(LindenmayerCurve):
|
||||
}
|
||||
def __init__(self, **kwargs):
|
||||
LindenmayerCurve.__init__(self, **kwargs)
|
||||
self.rotate(-self.order*np.pi/9)
|
||||
self.rotate(-self.order*np.pi/9, about_point = ORIGIN)
|
||||
|
||||
class SierpinskiCurve(LindenmayerCurve):
|
||||
CONFIG = {
|
||||
|
||||
@@ -260,7 +260,7 @@ class GraphScene(Scene):
|
||||
def annotate_edges(self, mobject, fade_in = True, **kwargs):
|
||||
angles = map(np.arctan, map(Line.get_slope, self.edges))
|
||||
self.edge_annotations = [
|
||||
mobject.copy().rotate(angle).shift(edge.get_center())
|
||||
mobject.copy().rotate(angle).move_to(edge.get_center())
|
||||
for angle, edge in zip(angles, self.edges)
|
||||
]
|
||||
if fade_in:
|
||||
|
||||
@@ -169,12 +169,15 @@ class Axes(VGroup):
|
||||
VGroup.__init__(self, **kwargs)
|
||||
self.x_axis = self.get_axis(self.x_min, self.x_max, self.x_axis_config)
|
||||
self.y_axis = self.get_axis(self.y_min, self.y_max, self.y_axis_config)
|
||||
self.y_axis.rotate(np.pi/2)
|
||||
self.y_axis.rotate(np.pi/2, about_point = ORIGIN)
|
||||
self.add(self.x_axis, self.y_axis)
|
||||
if self.three_d:
|
||||
self.z_axis = self.get_axis(self.z_min, self.z_max, self.z_axis_config)
|
||||
self.z_axis.rotate(-np.pi/2, UP)
|
||||
self.z_axis.rotate(angle_of_vector(self.z_normal), OUT)
|
||||
self.z_axis.rotate(-np.pi/2, UP, about_point = ORIGIN)
|
||||
self.z_axis.rotate(
|
||||
angle_of_vector(self.z_normal), OUT,
|
||||
about_point = ORIGIN
|
||||
)
|
||||
self.add(self.z_axis)
|
||||
|
||||
def get_axis(self, min_val, max_val, extra_config):
|
||||
|
||||
@@ -94,7 +94,7 @@ class Speedometer(VMobject):
|
||||
)
|
||||
needle.stretch_to_fit_width(self.needle_width)
|
||||
needle.stretch_to_fit_height(self.needle_height)
|
||||
needle.rotate(start_angle - np.pi/2)
|
||||
needle.rotate(start_angle - np.pi/2, about_point = ORIGIN)
|
||||
self.add(needle)
|
||||
self.needle = needle
|
||||
|
||||
@@ -245,8 +245,8 @@ class Laptop(VGroup):
|
||||
self.axis = axis
|
||||
|
||||
self.add(body, screen_plate, axis)
|
||||
self.rotate(5*np.pi/12, LEFT)
|
||||
self.rotate(np.pi/6, DOWN)
|
||||
self.rotate(5*np.pi/12, LEFT, about_point = ORIGIN)
|
||||
self.rotate(np.pi/6, DOWN, about_point = ORIGIN)
|
||||
|
||||
class PatreonLogo(SVGMobject):
|
||||
CONFIG = {
|
||||
|
||||
@@ -104,12 +104,12 @@ class VectorScene(Scene):
|
||||
|
||||
angle = vector.get_angle()
|
||||
if not rotate:
|
||||
label.rotate(-angle)
|
||||
label.rotate(-angle, about_point = ORIGIN)
|
||||
if direction is "left":
|
||||
label.shift(-label.get_bottom() + 0.1*UP)
|
||||
else:
|
||||
label.shift(-label.get_top() + 0.1*DOWN)
|
||||
label.rotate(angle)
|
||||
label.rotate(angle, about_point = ORIGIN)
|
||||
label.shift((vector.get_end() - vector.get_start())/2)
|
||||
return label
|
||||
|
||||
|
||||
Reference in New Issue
Block a user