본문 바로가기

Programming/Manim Project

흐르는 물결같은, 흐르는 사인 곡선 만들기

반응형

움직이는 사인 곡선을 만들어보자. 마치 파형이 이동하는 듯한.

 

 

기본 구상

$\sin ( \theta + \alpha )$는 $\sin \theta$인 곡선이 $\alpha$만큼 왼쪽으로 쉬프트 된 곡선이다. 

 

 

위 그림은 $\sin \theta$를 $\frac {\pi} {4}$ 만큼씩 왼쪽으로 이동한 것으로, 시간 단위별로 이렇게 이동시키면, 마치 사인파가 왼쪽으로 흐르는 듯한 효과를 낼 수 있을 것이다.

 

코딩

축 그리기

x축과 y축을 그린다. 

 

 

    def draw_axis(self):
        x_axis = Line(np.array([-4,0,0]), np.array([4,0,0]))
        y_axis = Line(np.array([-4,2,0]), np.array([-4,-2,0]))

        self.add(x_axis, y_axis)
        self.x_min = -4
        self.x_max = 4

나중에 사인 그래프를 그릴 때, x축 최솟값과 최댓값을 사용하기 위해 self.x_min=-4, self.x_max=4로 해서 전역 변수로 저장해 둔다.

 

사인 웨이브 그리기

기본 전략은 다음과 같다.

  • $\sin x$에 대한 그래프를 그린다. 
  • 프레임이 변할 때 마다 dx 값이 커지게 하고, $\sin (x+dx)$ 그래프로 업데이트되게 한다. 

$\sin x$에 대한 그래프는, 계속해서 만들어져야 하기에 그래프를 얻어내는 것을 함수로 만들어두자.

    def get_sine_wave(self, dx=0):
        return FunctionGraph(
            # sin(0)부터 시작하게 하기 위함임. x_min=-4이기에 4를 더해줘서 0을 만듦
            lambda x: np.sin((x-self.x_min + dx)),
            x_min=self.x_min, x_max=self.x_max
        )

 

먼저 최초 사인 그래프를 생성해서 화면에 표출한다.

sine_wave = self.get_sine_wave()
self.add(sine_wave)

 

이제 dx를 조금씩 커지게 하면서 sine_wave를 업데이트 하면 된다.

 

dx를 조금씩 커지게 하는 것은 ValueTracker를 이용하자.

초기값은 0으로 하고, 4초 동안에 0 ~ $2 \pi$까지 서서히 증가하게 한다.

vt = ValueTracker(0)

moving_time = 4
moving_length = 2*PI
self.play(vt.set_value, moving_length, run_time=moving_time, rate_func=linear)

 

sine_wave가 영상 프레임마다 변하게 하는 것은, add_updater(update_wave)와 같이해서 프레임마다 update_wave 함수가 호출되도록 하고, 이 함수 내에서 새로운 그래프를 얻어내고, 그 그래프로 sine_wave가 업데이트되도록 한다.

        def update_wave(wave):
            wave.become(self.get_sine_wave(dx=vt.get_value()))

        sine_wave.add_updater(update_wave)

 

전체 소스는 다음과 같다.

from manimlib.imports import *

class MovingWave(Scene):
    def construct(self):
        self.draw_axis()
        self.draw_sine_wave()

    def draw_axis(self):
        x_axis = Line(np.array([-4,0,0]), np.array([4,0,0]))
        y_axis = Line(np.array([-4,2,0]), np.array([-4,-2,0]))

        self.add(x_axis, y_axis)
        self.x_min = -4
        self.x_max = 4

    def draw_sine_wave(self):
        sine_wave = self.get_sine_wave()
        vt = ValueTracker(0)

        def update_wave(wave):
            wave.become(self.get_sine_wave(dx=vt.get_value()))

        sine_wave.add_updater(update_wave)

        self.add(sine_wave)
        self.wait(2)

        # 사인파가 4초에 2PI 만큼 이동하게
        moving_time = 4
        moving_length = 2*PI
        self.play(vt.set_value, moving_length, run_time=moving_time, rate_func=linear)
        self.wait()


    def get_sine_wave(self, dx=0):
        return FunctionGraph(
            # sin(0)부터 시작하게 하기 위함임. x_min=-4이기에 4를 더해줘서 0을 만듦
            lambda x: np.sin((x-self.x_min + dx)),
            x_min=self.x_min, x_max=self.x_max
        )

 

만들어진 동영상

 

-끝-

반응형