The scene is simple, one Line and rotate PI/2 with below code:
ln = Line(ORIGIN, RIGHT*2)
self.add(ln)
self.wait()
self.play(ApplyMethod(ln.rotate, PI/2, OUT))
However, during the rotating, seemingly scaling at the same time, I check the axis is [0 0 1] that is z axis, I suppose the length of the line should be kept unchanged.
How to prevent the line from scaling? Thanks!
Use Rotate
or Rotating
, see this.
class RotateVector(Scene):
def construct(self):
coord_start=[1,1,0]
coord_end=[2,3,0]
dot_start=Dot().move_to(coord_start)
dot_end=Dot().move_to(coord_end)
vector=Arrow(coord_start,coord_end,buff=0)
vector.set_color(RED)
self.add(dot_start,dot_end)
self.play(GrowArrow(vector))
self.play(
Rotating(
vector,
radians=PI*2,
about_point=coord_start,
rate_func=smooth,
run_time=1
)
)
self.wait()
self.play(
Rotating(
vector,
radians=PI*2,
about_point=coord_end,
rate_func=linear,
run_time=1
)
)
self.wait()
You can create a custom animation:
class RotatingAndMove(Animation):
CONFIG = {
"axis": OUT,
"radians": TAU,
"run_time": 5,
"rate_func": linear,
"about_point": None,
"about_edge": None,
}
def __init__(self, mobject, direction,**kwargs):
assert(isinstance(mobject, Mobject))
digest_config(self, kwargs)
self.mobject = mobject
self.direction = direction
def interpolate_mobject(self, alpha):
self.mobject.become(self.starting_mobject)
self.mobject.rotate(
alpha * self.radians,
axis=self.axis,
about_point=self.about_point,
about_edge=self.about_edge,
)
self.mobject.shift(alpha*self.direction)
class NewSceneRotate(Scene):
def construct(self):
arrow=Vector(UP)
arrow.to_corner(UL)
self.play(GrowArrow(arrow))
self.play(
RotatingAndMove(arrow,RIGHT*12+DOWN*4)
)
self.wait()
Or you can use UpdateFromAlphaFunc
:
class NewSceneRotateUpdate(Scene):
def construct(self):
arrow=Vector(UP)
arrow.to_corner(UL)
direction=RIGHT*12+DOWN*4
radians=TAU
arrow.starting_mobject=arrow.copy()
def update_arrow(mob,alpha):
mob.become(mob.starting_mobject)
mob.rotate(alpha*radians)
mob.shift(alpha*direction)
self.play(GrowArrow(arrow))
self.play(
UpdateFromAlphaFunc(arrow,update_arrow,rate_func=linear,run_time=5)
)
self.wait()
Something that should be very clear is that when you define an update function, it is not the same to use dt as alpha. That is, it is not the same to define
def update_function(mob,dt)
as
def update_function(mob,alpha)
dt varies with the fps of the video, and is calculated as follows:
dt = 1/self.camera.frame_rate
# You don't have to calculate it, manim already does it by default,
# I just write it so you know where it comes from.
Where self
refers to the Scene
class.
And alpha varies from 0 to 1, in fact, you can write the previus scene with this update method and get the same result:
def update_arrow(mob,dt):
alpha=interpolate(0,1,dt)
mob.become(mob.starting_mobject)
mob.rotate(alpha*radians)
mob.shift(alpha*direction)
This can be useful if you want alpha to vary in different intervals, use
alpha=interpolate(alpha_start,alpha_end,dt)