반응형
사인(Sine)과 코사인(Cosine) 그래프가 왜 그렇게 그려지는지 설명할 때 많이 쓰이는 방법은 다음과 같다.
- 반지름이 1인 원을 그리고, 원의 중심에서 그 원둘레의 임의의 점까지의 직선을 그린 후, x축과 그 직선 간의 사잇각을 $ \theta $라 하자
- 이 $ \theta $에 대해 $\sin \theta = 세로 $가 되고, $ \cos \theta = 가로$가 된다.
- 따라서, 그 어떤 점을 원둘레로 이동시키면, $ \theta $가 커지고, 이에 따라 $\sin \theta $의 값이 변하게 되는데, 이를 원 오른편에 가로축을 그리고, 그 위를 $\theta$의 변화값으로 두고, 세로축에 '세로 길이'를 표시하면, 이게 $ \sin \theta $ 값이 된다. 즉, 사인(Sine) 그래프가 된다.
- 코사인에 대한 것은 $ \cos \theta $가 '가로' 값이기에, 원의 중심에서 아래 편으로 직선을 내려서 축 선으로 삼고, 이 축 선을 따라 $ \theta $의 값이 커지는 것으로 하고, 이 $\theta$값에 대한 '가로길이' 값을 그려나가면, 이게 $\cos \theta$ 그래프가 된다.
사인 곡선만 그리는 것은 여기 참조
프로그램에 대한 전체 스케치는,
먼저 축 라인과 원을 그리자
원을 중심으로 해서, 가로축은 사인 곡선을, 세로축에는 코사인 곡선을 나타낼 것이다.
class SineCosine_Curve(Scene):
def construct(self):
self.show_axis()
self.show_circle()
self.wait()
def show_axis(self):
x_start = np.array([-6,2,0])
x_end = np.array([3,2,0])
y_start = np.array([-4,-3,0])
y_end = np.array([-4,3.5,0])
x_axis = Line(x_start, x_end)
y_axis = Line(y_start, y_end)
self.add(x_axis, y_axis)
self.add_xy_labels()
self.orgin_point = np.array([-4,2,0])
self.curve_start = np.array([-3,2,0])
def add_xy_labels(self):
x_labels = [
TexMobject("\pi"), TexMobject("2 \pi"),
TexMobject("3 \pi"), TexMobject("4 \pi"),
]
y_labels = [
TexMobject("\pi"), TexMobject("2 \pi"),
TexMobject("3 \pi"), TexMobject("4 \pi"),
]
for i in range(len(x_labels)): # -2 -1 0 1
x_labels[i].scale(0.6)
x_labels[i].next_to(np.array([-2+i,2,0]), DOWN )
self.add(x_labels[i])
for i in range(len(y_labels)): # 1 0 -1 -2
y_labels[i].scale(0.6)
y_labels[i].rotate(-PI/2)
y_labels[i].next_to(np.array([-4, 1-i,0]), LEFT )
self.add(y_labels[i])
def show_circle(self):
circle = Circle(radius=1)
circle.move_to(self.orgin_point)
self.add(circle)
self.circle = circle
원 위의 점이 자동으로 움직이게 하자
원과 x축(가로 선)이 만나는 지점에 점을 그리고, 이 점이 원둘레를 따라 돌게 만들 것이다.
자동으로 점이 움직이게 하는 것은 dot.add_updater(go_around_circle)을 통해서 이루어진다.
def move_dot_and_draw_curve(self):
orbit = self.circle
orgin_point = self.orgin_point
dot = Dot(radius=0.08, color=YELLOW)
dot.move_to(orbit.point_from_proportion(0))
self.t_offset = 0
rate = 0.25
def go_around_circle(mob, dt):
self.t_offset += (dt * rate)
# print(self.t_offset)
mob.move_to(orbit.point_from_proportion(self.t_offset % 1))
dot.add_updater(go_around_circle) #move dot around the circle
self.add(dot, orbit)
self.wait(8.5)
dot.remove_updater(go_around_circle)
점의 움직임에 따라, 사인/코사인 곡선이 그려지도록 하자
점(dot)이 움직임에 따라 다음 5개의 라인이 새로 그려지게 한다.
이에 해당하는 코드는 다음과 같다.
origin_to_circle_line = always_redraw(get_line_to_circle) # from circle origin to dot
dot_to_sine_line = always_redraw(get_line_to_sine) # from dot to sine curve
sine_curve_line = always_redraw(get_sine_curve) # sine curve
dot_to_cosine_line = always_redraw(get_line_to_cosine) # from dot to cosine curve
cosine_curve_line = always_redraw(get_cosine_curve) # cosine curve
위 코드를 보면 always_redraw 함수를 이용하고 있는데, always_redraw 함수는 인자로 주어지는 메서드를 프레임이 바뀔 때마다 호출하고, 원래의 객체를 그 메서드가 리턴하는 객체로 교체한다.
always_redraw의 인자로 사용되도록 코딩한 각 메서드는 다음과 같다.
def go_around_circle(mob, dt):
self.t_offset += (dt * rate)
# print(self.t_offset)
mob.move_to(orbit.point_from_proportion(self.t_offset % 1))
def get_line_to_circle():
return Line(orgin_point, dot.get_center(), color=BLUE)
### sine
def get_line_to_sine():
x = self.curve_start[0] + self.t_offset * 2
y = dot.get_center()[1]
return Line(dot.get_center(), np.array([x,y,0]), color=YELLOW_A, stroke_width=2 )
self.sine_curve = VGroup()
self.sine_curve.add(Line(self.curve_start,self.curve_start))
def get_sine_curve():
last_line = self.sine_curve[-1]
x = self.curve_start[0] + self.t_offset * 2
y = dot.get_center()[1]
new_line = Line(last_line.get_end(),np.array([x,y,0]), color=YELLOW_D)
self.sine_curve.add(new_line)
return self.sine_curve
### cosine
def get_line_to_cosine():
x = dot.get_center()[0]
y = self.curve_start[1] - self.t_offset * 2
return Line(dot.get_center(), np.array([x,y,0]), color=YELLOW_A, stroke_width=2 )
self.cosine_curve = VGroup()
self.cosine_curve.add(Line(self.curve_start, self.curve_start))
def get_cosine_curve():
last_line = self.cosine_curve[-1]
x = dot.get_center()[0]
y = self.curve_start[1] - self.t_offset * 2
new_line = Line(last_line.get_end(), np.array([x, y, 0]), color=YELLOW_D)
self.cosine_curve.add(new_line)
return self.cosine_curve
모든 사항을 반영한 코드 및 실행 동영상은 다음과 같다.
from manimlib.imports import *
class SineCosine_Curve(Scene):
def construct(self):
self.show_axis()
self.show_circle()
self.move_dot_and_draw_curve()
self.wait()
def show_axis(self):
x_start = np.array([-6,2,0])
x_end = np.array([3,2,0])
y_start = np.array([-4,-3,0])
y_end = np.array([-4,3.5,0])
x_axis = Line(x_start, x_end)
y_axis = Line(y_start, y_end)
self.add(x_axis, y_axis)
self.add_xy_labels()
self.orgin_point = np.array([-4,2,0])
self.curve_start = np.array([-3,2,0])
def add_xy_labels(self):
x_labels = [
TexMobject("\pi"), TexMobject("2 \pi"),
TexMobject("3 \pi"), TexMobject("4 \pi"),
]
y_labels = [
TexMobject("\pi"), TexMobject("2 \pi"),
TexMobject("3 \pi"), TexMobject("4 \pi"),
]
for i in range(len(x_labels)): # -2 -1 0 1
x_labels[i].scale(0.6)
x_labels[i].next_to(np.array([-2+i,2,0]), DOWN )
self.add(x_labels[i])
for i in range(len(y_labels)): # 1 0 -1 -2
y_labels[i].scale(0.6)
y_labels[i].rotate(-PI/2)
y_labels[i].next_to(np.array([-4, 1-i,0]), LEFT )
self.add(y_labels[i])
def show_circle(self):
circle = Circle(radius=1)
circle.move_to(self.orgin_point)
self.add(circle)
self.circle = circle
def move_dot_and_draw_curve(self):
orbit = self.circle
orgin_point = self.orgin_point
dot = Dot(radius=0.08, color=YELLOW)
dot.move_to(orbit.point_from_proportion(0))
self.t_offset = 0
rate = 0.25
def go_around_circle(mob, dt):
self.t_offset += (dt * rate)
# print(self.t_offset)
mob.move_to(orbit.point_from_proportion(self.t_offset % 1))
def get_line_to_circle():
return Line(orgin_point, dot.get_center(), color=BLUE)
### sine
def get_line_to_sine():
x = self.curve_start[0] + self.t_offset * 2
y = dot.get_center()[1]
return Line(dot.get_center(), np.array([x,y,0]), color=YELLOW_A, stroke_width=2 )
self.sine_curve = VGroup()
self.sine_curve.add(Line(self.curve_start,self.curve_start))
def get_sine_curve():
last_line = self.sine_curve[-1]
x = self.curve_start[0] + self.t_offset * 2
y = dot.get_center()[1]
new_line = Line(last_line.get_end(),np.array([x,y,0]), color=YELLOW_D)
self.sine_curve.add(new_line)
return self.sine_curve
### cosine
def get_line_to_cosine():
x = dot.get_center()[0]
y = self.curve_start[1] - self.t_offset * 2
return Line(dot.get_center(), np.array([x,y,0]), color=YELLOW_A, stroke_width=2 )
self.cosine_curve = VGroup()
self.cosine_curve.add(Line(self.curve_start, self.curve_start))
def get_cosine_curve():
last_line = self.cosine_curve[-1]
x = dot.get_center()[0]
y = self.curve_start[1] - self.t_offset * 2
new_line = Line(last_line.get_end(), np.array([x, y, 0]), color=YELLOW_D)
self.cosine_curve.add(new_line)
return self.cosine_curve
dot.add_updater(go_around_circle) #move dot around the circle
origin_to_circle_line = always_redraw(get_line_to_circle) # from circle origin to dot
dot_to_sine_line = always_redraw(get_line_to_sine) # from dot to sine curve
sine_curve_line = always_redraw(get_sine_curve) # sine curve
dot_to_cosine_line = always_redraw(get_line_to_cosine) # from dot to cosine curve
cosine_curve_line = always_redraw(get_cosine_curve) # cosine curve
self.add(dot, orbit)
self.add(origin_to_circle_line,
dot_to_sine_line, sine_curve_line,
dot_to_cosine_line, cosine_curve_line,
)
self.wait(8.5)
dot.remove_updater(go_around_circle)
-끝-
반응형
'Programming > Manim Project' 카테고리의 다른 글
계속해서 흘러가는 사인 파형 만들기 (0) | 2020.09.17 |
---|---|
흐르는 물결같은, 흐르는 사인 곡선 만들기 (0) | 2020.09.17 |
원 위의 점이 이동하면서 사인 곡선 그리기 (1) | 2020.09.14 |
python의 for 루프 설명하기 (0) | 2020.05.31 |
[컴포넌트]VerticalBarChart 만들기 (3. 사용법) (0) | 2020.05.17 |