mirror of
https://github.com/3b1b/manim.git
synced 2025-11-14 23:27:45 +00:00
Tiny nudges for of div and curl
This commit is contained in:
parent
d72483e909
commit
71400a3941
1 changed files with 545 additions and 32 deletions
|
|
@ -4,7 +4,7 @@ DEFAULT_SCALAR_FIELD_COLORS = [BLUE_E, GREEN, YELLOW, RED]
|
|||
|
||||
# Quick note to anyone coming to this file with the
|
||||
# intent of recreating animations from the video. Some
|
||||
# of these, espeically those involving StreamLineAnimation,
|
||||
# of these, especially those involving StreamLineAnimation,
|
||||
# can take an extremely long time to run, but much of the
|
||||
# computational cost is just for giving subtle little effects
|
||||
# which don't matter too much. Switching the line_anim_class
|
||||
|
|
@ -14,6 +14,8 @@ DEFAULT_SCALAR_FIELD_COLORS = [BLUE_E, GREEN, YELLOW, RED]
|
|||
# run at production quality.
|
||||
|
||||
FOX_COLOR = "#DF7F20"
|
||||
RABBIT_COLOR = "#C6D6EF"
|
||||
|
||||
|
||||
# Helper functions
|
||||
def get_flow_start_points(x_min=-8, x_max=8,
|
||||
|
|
@ -301,6 +303,7 @@ class VectorField(VGroup):
|
|||
"stroke_color": BLACK,
|
||||
"stroke_width": 0.5,
|
||||
"fill_opacity": 1.0,
|
||||
"vector_config": {},
|
||||
}
|
||||
|
||||
def __init__(self, func, **kwargs):
|
||||
|
|
@ -317,19 +320,22 @@ class VectorField(VGroup):
|
|||
point = x * RIGHT + y * UP
|
||||
self.add(self.get_vector(point))
|
||||
|
||||
def get_vector(self, point):
|
||||
def get_vector(self, point, **kwargs):
|
||||
output = np.array(self.func(point))
|
||||
norm = np.linalg.norm(output)
|
||||
if norm == 0:
|
||||
output *= 0
|
||||
else:
|
||||
output *= self.length_func(norm) / norm
|
||||
vect = Vector(output)
|
||||
vector_config = dict(self.vector_config)
|
||||
vector_config.update(kwargs)
|
||||
vect = Vector(output, **vector_config)
|
||||
vect.shift(point)
|
||||
fill_color = rgb_to_color(
|
||||
self.rgb_gradient_function(np.array([norm]))[0]
|
||||
)
|
||||
vect.set_fill(fill_color, self.fill_opacity)
|
||||
vect.set_color(fill_color)
|
||||
vect.set_fill(opacity=self.fill_opacity)
|
||||
vect.set_stroke(
|
||||
self.stroke_color,
|
||||
self.stroke_width
|
||||
|
|
@ -456,6 +462,22 @@ class JigglingSubmobjects(ContinualAnimation):
|
|||
# Scenes
|
||||
|
||||
|
||||
class Introduction(MovingCameraScene):
|
||||
def construct(self):
|
||||
self.show_divergence()
|
||||
self.show_curl()
|
||||
self.show_context()
|
||||
|
||||
def show_divergence(self):
|
||||
pass
|
||||
|
||||
def show_curl(self):
|
||||
pass
|
||||
|
||||
def show_context(self):
|
||||
pass
|
||||
|
||||
|
||||
class TestVectorField(Scene):
|
||||
CONFIG = {
|
||||
"func": cylinder_flow_vector_field,
|
||||
|
|
@ -476,7 +498,7 @@ class TestVectorField(Scene):
|
|||
self.wait(10)
|
||||
|
||||
|
||||
class Introduction(Scene):
|
||||
class CylinderModel(Scene):
|
||||
CONFIG = {
|
||||
"production_quality_flow": True,
|
||||
"vector_field_func": cylinder_flow_vector_field,
|
||||
|
|
@ -735,7 +757,7 @@ class Introduction(Scene):
|
|||
)
|
||||
|
||||
|
||||
class ElectricField(Introduction, MovingCameraScene):
|
||||
class ElectricField(CylinderModel, MovingCameraScene):
|
||||
def construct(self):
|
||||
self.add_plane()
|
||||
self.add_title()
|
||||
|
|
@ -1232,7 +1254,7 @@ class TotallyToScale(Scene):
|
|||
|
||||
|
||||
# TODO: Revisit this
|
||||
class FluidFlowAsHillGradient(Introduction, ThreeDScene):
|
||||
class FluidFlowAsHillGradient(CylinderModel, ThreeDScene):
|
||||
CONFIG = {
|
||||
"production_quality_flow": False,
|
||||
}
|
||||
|
|
@ -1756,13 +1778,6 @@ class DivergenceAsNewFunction(Scene):
|
|||
|
||||
class DivergenceZeroCondition(Scene):
|
||||
def construct(self):
|
||||
self.add_vector_field()
|
||||
self.add_title()
|
||||
self.begin_flow()
|
||||
self.add_circle()
|
||||
self.wait(5)
|
||||
|
||||
def add_title(self):
|
||||
title = TextMobject(
|
||||
"For actual (incompressible) fluid flow:"
|
||||
)
|
||||
|
|
@ -1775,6 +1790,15 @@ class DivergenceZeroCondition(Scene):
|
|||
for mob in title, equation:
|
||||
mob.add_background_rectangle(buff=MED_SMALL_BUFF / 2)
|
||||
self.add_foreground_mobjects(mob)
|
||||
self.wait(1)
|
||||
|
||||
|
||||
class PureCylinderFlow(Scene):
|
||||
def construct(self):
|
||||
self.add_vector_field()
|
||||
self.begin_flow()
|
||||
self.add_circle()
|
||||
self.wait(5)
|
||||
|
||||
def add_vector_field(self):
|
||||
vector_field = VectorField(
|
||||
|
|
@ -1800,18 +1824,35 @@ class DivergenceZeroCondition(Scene):
|
|||
if np.linalg.norm(stream_line.points[0]) < 1:
|
||||
stream_lines.remove(stream_line)
|
||||
|
||||
self.modify_flow(stream_lines)
|
||||
|
||||
stream_line_animation = StreamLineAnimation(stream_lines)
|
||||
stream_line_animation.update(3)
|
||||
|
||||
self.add(stream_line_animation)
|
||||
|
||||
def add_circle(self):
|
||||
self.add_foreground_mobjects(Circle(
|
||||
circle = Circle(
|
||||
radius=1,
|
||||
stroke_color=YELLOW,
|
||||
fill_color=BLACK,
|
||||
fill_opacity=1,
|
||||
))
|
||||
num_anchors=24,
|
||||
)
|
||||
self.modify_flow(circle)
|
||||
self.add_foreground_mobjects()
|
||||
|
||||
def modify_flow(self, mobject):
|
||||
pass
|
||||
|
||||
|
||||
class PureAirfoilFlow(PureCylinderFlow):
|
||||
def modify_flow(self, mobject):
|
||||
vect = 0.1 * UP + 0.2 * LEFT
|
||||
mobject.scale(np.linalg.norm(vect - RIGHT))
|
||||
mobject.shift(vect)
|
||||
mobject.apply_complex_function(joukowsky_map)
|
||||
return mobject
|
||||
|
||||
|
||||
class IntroduceCurl(IntroduceVectorField):
|
||||
|
|
@ -2502,7 +2543,7 @@ class ShowTwoPopulations(Scene):
|
|||
examples.arrange_submobjects(LEFT, buff=2)
|
||||
|
||||
preditor, prey = words = VGroup(
|
||||
TextMobject("Preditor"),
|
||||
TextMobject("Predator"),
|
||||
TextMobject("Prey")
|
||||
)
|
||||
for mob, word in zip(examples, words):
|
||||
|
|
@ -2524,11 +2565,9 @@ class ShowTwoPopulations(Scene):
|
|||
group[1:],
|
||||
run_time=4,
|
||||
lag_ratio=0.1,
|
||||
rate_func=lambda t: np.clip(smooth(2 * t), 0, 1)
|
||||
)
|
||||
for group in [
|
||||
foxes[:self.start_num_foxes],
|
||||
rabbits[:self.start_num_rabbits],
|
||||
]
|
||||
for group in [foxes, rabbits]
|
||||
]
|
||||
)
|
||||
|
||||
|
|
@ -2536,8 +2575,8 @@ class ShowTwoPopulations(Scene):
|
|||
foxes = self.foxes
|
||||
rabbits = self.rabbits
|
||||
phase_point = VectorizedPoint(
|
||||
self.start_num_foxes * RIGHT +
|
||||
self.start_num_rabbits * UP
|
||||
self.start_num_rabbits * RIGHT +
|
||||
self.start_num_foxes * UP
|
||||
)
|
||||
self.add(VectorFieldFlow(
|
||||
phase_point,
|
||||
|
|
@ -2629,7 +2668,8 @@ class ShowTwoPopulations(Scene):
|
|||
return self.get_animal("fox", FOX_COLOR)
|
||||
|
||||
def get_rabbit(self):
|
||||
return self.get_animal("rabbit", WHITE)
|
||||
# return self.get_animal("rabbit", WHITE)
|
||||
return self.get_animal("bunny", RABBIT_COLOR)
|
||||
|
||||
def get_pop_labels(self):
|
||||
labels = VGroup(
|
||||
|
|
@ -2773,18 +2813,18 @@ class PhaseSpaceOfPopulationModel(ShowTwoPopulations, PiCreatureScene, MovingCam
|
|||
self.pop_sizes_updates = pop_sizes_updates
|
||||
|
||||
def write_differential_equations(self):
|
||||
variables = ["XX", "YY"]
|
||||
variables = ["X", "YY"]
|
||||
equations = TexMobject(
|
||||
"""
|
||||
{dXX \\over dt} =
|
||||
30 \\cdot XX - XX \\cdot YY \\\\
|
||||
{dX \\over dt} =
|
||||
X \\cdot (\\alpha - \\beta YY \\,) \\\\
|
||||
\\quad \\\\
|
||||
{dYY \\over dt} =
|
||||
XX \\cdot YY - 30 \\cdot YY
|
||||
YY \\cdot (\\delta X - \\gamma)
|
||||
""",
|
||||
substrings_to_isolate=variables
|
||||
)
|
||||
animals = [self.get_fox().flip(), self.get_rabbit()]
|
||||
animals = [self.get_rabbit(), self.get_fox().flip()]
|
||||
for char, animal in zip(variables, animals):
|
||||
for part in equations.get_parts_by_tex(char):
|
||||
animal_copy = animal.copy()
|
||||
|
|
@ -3191,7 +3231,7 @@ class ShowDotProduct(MovingCameraScene):
|
|||
def get_product(self, v1, v2):
|
||||
return np.dot(v1.get_vector(), v2.get_vector())
|
||||
|
||||
def add_additional_continual_animations(self):
|
||||
def add_additional_continual_animations(self, v1, v2):
|
||||
pass
|
||||
|
||||
|
||||
|
|
@ -3224,6 +3264,479 @@ class ShowCrossProduct(ShowDotProduct):
|
|||
))
|
||||
|
||||
|
||||
class NewSceneName(Scene):
|
||||
class DivergenceTinyNudgesView(MovingCameraScene):
|
||||
CONFIG = {
|
||||
"scale_factor": 0.25
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
pass
|
||||
self.add_vector_field()
|
||||
self.zoom_in()
|
||||
self.take_tiny_step()
|
||||
self.show_dot_product()
|
||||
self.show_circle_of_values()
|
||||
self.switch_to_curl_words()
|
||||
self.rotate_difference_vectors()
|
||||
|
||||
def add_vector_field(self):
|
||||
plane = self.plane = NumberPlane()
|
||||
|
||||
vector_field = self.vector_field = VectorField(
|
||||
lambda p: 0.4 * np.array([
|
||||
np.cos(3 * p[0] * p[1] / 4),
|
||||
np.sin(TAU * p[1] / 4),
|
||||
0
|
||||
]),
|
||||
length_func=lambda n: max(n, 0.5),
|
||||
max_magnitude=1.0,
|
||||
)
|
||||
self.add(plane)
|
||||
self.add(vector_field)
|
||||
|
||||
def zoom_in(self):
|
||||
point = self.point = 2 * LEFT + UP
|
||||
vector_field = self.vector_field
|
||||
sf = self.scale_factor
|
||||
|
||||
self.play(
|
||||
self.camera_frame.scale, sf,
|
||||
self.camera_frame.move_to, point,
|
||||
FadeOut(vector_field),
|
||||
run_time=2
|
||||
)
|
||||
vector_field.vector_config.update({
|
||||
"rectangular_stem_width": 0.02,
|
||||
"tip_length": 0.1
|
||||
})
|
||||
vector = vector_field.get_vector(point)
|
||||
|
||||
input_dot = Dot(point).scale(sf)
|
||||
input_words = TextMobject("$(x_0, y_0)$").scale(sf)
|
||||
input_words.next_to(input_dot, DL, SMALL_BUFF * sf)
|
||||
output_words = TextMobject("Output").scale(sf)
|
||||
output_words.add_background_rectangle()
|
||||
output_words.next_to(vector.get_top(), UP, sf * SMALL_BUFF)
|
||||
output_words.match_color(vector)
|
||||
|
||||
self.add_foreground_mobjects(input_dot)
|
||||
self.play(
|
||||
FadeInAndShiftFromDirection(input_dot, SMALL_BUFF * DL),
|
||||
Write(input_words),
|
||||
)
|
||||
self.play(
|
||||
GrowArrow(vector),
|
||||
Write(output_words),
|
||||
)
|
||||
self.wait()
|
||||
|
||||
self.set_variables_as_attrs(
|
||||
point, vector, input_dot,
|
||||
input_words, output_words,
|
||||
)
|
||||
|
||||
def take_tiny_step(self):
|
||||
sf = self.scale_factor
|
||||
vector_field = self.vector_field
|
||||
point = self.point
|
||||
vector = self.vector
|
||||
output_words = self.output_words
|
||||
input_dot = self.input_dot
|
||||
|
||||
nudge = 0.5 * RIGHT
|
||||
nudged_point = point + nudge
|
||||
|
||||
new_vector = vector_field.get_vector(nudged_point)
|
||||
new_vector.set_color(YELLOW)
|
||||
new_dot = Dot(nudged_point).scale(sf)
|
||||
step_vector = Arrow(
|
||||
point, nudged_point,
|
||||
buff=0,
|
||||
color=TEAL,
|
||||
**vector_field.vector_config
|
||||
)
|
||||
step_vector.set_stroke(BLACK, 0.5)
|
||||
|
||||
new_output_words = TextMobject("New output").scale(sf)
|
||||
new_output_words.add_background_rectangle()
|
||||
new_output_words.next_to(new_vector.get_end(), UP, sf * SMALL_BUFF)
|
||||
new_output_words.match_color(new_vector)
|
||||
step_words = TextMobject("Step").scale(sf)
|
||||
step_words.next_to(step_vector, UP, buff=0)
|
||||
step_words.set_color(step_vector.get_fill_color())
|
||||
step_words.add_background_rectangle()
|
||||
small_step_words = TextMobject("(think tiny step)").scale(sf)
|
||||
small_step_words.next_to(
|
||||
step_words, RIGHT,
|
||||
buff=sf * MED_SMALL_BUFF,
|
||||
)
|
||||
small_step_words.add_background_rectangle()
|
||||
small_step_words.match_style(step_words)
|
||||
|
||||
shifted_vector = vector.copy().shift(nudge)
|
||||
diff_vector = Arrow(
|
||||
shifted_vector.get_end(),
|
||||
new_vector.get_end(),
|
||||
buff=0,
|
||||
color=RED,
|
||||
**vector_field.vector_config
|
||||
)
|
||||
diff_words = TextMobject("Difference").scale(sf)
|
||||
diff_words.add_background_rectangle()
|
||||
diff_words.next_to(diff_vector.get_start(), UR, buff=2 * sf * SMALL_BUFF)
|
||||
diff_words.match_color(diff_vector)
|
||||
diff_words.rotate(
|
||||
diff_vector.get_angle(),
|
||||
about_point=diff_vector.get_start()
|
||||
)
|
||||
|
||||
self.play(
|
||||
GrowArrow(step_vector),
|
||||
Write(step_words),
|
||||
ReplacementTransform(input_dot.copy(), new_dot)
|
||||
)
|
||||
self.add_foreground_mobjects(new_dot)
|
||||
self.play(FadeIn(small_step_words))
|
||||
self.play(FadeOut(small_step_words))
|
||||
self.play(
|
||||
ReplacementTransform(vector.copy(), new_vector),
|
||||
ReplacementTransform(output_words.copy(), new_output_words),
|
||||
)
|
||||
self.wait()
|
||||
self.play(ReplacementTransform(
|
||||
vector.copy(), shifted_vector,
|
||||
path_arc=-TAU / 4
|
||||
))
|
||||
self.wait()
|
||||
self.play(
|
||||
FadeOut(output_words),
|
||||
FadeOut(new_output_words),
|
||||
GrowArrow(diff_vector),
|
||||
Write(diff_words)
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
vector.scale, 0, {"about_point": vector.get_start()},
|
||||
shifted_vector.scale, 0, {"about_point": shifted_vector.get_start()},
|
||||
ReplacementTransform(
|
||||
new_vector,
|
||||
diff_vector.copy().shift(-vector.get_vector()),
|
||||
remover=True
|
||||
),
|
||||
diff_vector.shift, -vector.get_vector(),
|
||||
MaintainPositionRelativeTo(diff_words, diff_vector),
|
||||
run_time=2
|
||||
)
|
||||
self.wait()
|
||||
|
||||
self.set_variables_as_attrs(
|
||||
step_vector, step_words,
|
||||
diff_vector, diff_words,
|
||||
)
|
||||
|
||||
def show_dot_product(self):
|
||||
sf = self.scale_factor
|
||||
point = self.point
|
||||
step_vector = self.step_vector
|
||||
step_words = self.step_words
|
||||
diff_vector = self.diff_vector
|
||||
diff_words = self.diff_words
|
||||
vects = VGroup(step_vector, diff_vector)
|
||||
|
||||
moving_step_vector = step_vector.copy()
|
||||
moving_diff_vector = diff_vector.copy()
|
||||
|
||||
def update_moving_diff_vector(dv):
|
||||
step = moving_step_vector.get_vector()
|
||||
o1 = self.vector_field.get_vector(point).get_vector()
|
||||
o2 = self.vector_field.get_vector(point + step).get_vector()
|
||||
diff = o2 - o1
|
||||
dv.put_start_and_end_on(
|
||||
moving_step_vector.get_end(),
|
||||
moving_step_vector.get_end() + diff,
|
||||
)
|
||||
self.moving_diff_vector_update = ContinualUpdateFromFunc(
|
||||
moving_diff_vector,
|
||||
update_moving_diff_vector
|
||||
)
|
||||
self.add(self.moving_diff_vector_update)
|
||||
|
||||
div_text = self.get_operator_text("div")
|
||||
|
||||
step_words_copy = step_words.copy()
|
||||
diff_words_copy = diff_words.copy()
|
||||
copies = VGroup(step_words_copy, diff_words_copy)
|
||||
|
||||
substrings = ["Step", "Difference"]
|
||||
dot_product = TextMobject(
|
||||
"(Step) $\\cdot$ (Difference)",
|
||||
substrings_to_isolate=substrings,
|
||||
arg_separator="",
|
||||
).scale(sf)
|
||||
group = VGroup(div_text, dot_product)
|
||||
group.arrange_submobjects(RIGHT, buff=sf * MED_SMALL_BUFF)
|
||||
group.next_to(
|
||||
self.camera_frame.get_top(), DOWN,
|
||||
buff=sf * MED_SMALL_BUFF
|
||||
)
|
||||
|
||||
for substring, mob, vect in zip(substrings, copies, vects):
|
||||
part = dot_product.get_part_by_tex(substring)
|
||||
mob.generate_target()
|
||||
mob.target.rotate(-vect.get_angle())
|
||||
mob.target.replace(part)
|
||||
# part.set_fill(opacity=0)
|
||||
part.match_color(mob)
|
||||
dot_product.add_background_rectangle()
|
||||
|
||||
brace = Brace(
|
||||
dot_product.copy().scale(1 / sf, about_point=ORIGIN), DOWN,
|
||||
buff=SMALL_BUFF
|
||||
).scale(sf, about_point=ORIGIN)
|
||||
dp_kwargs = {
|
||||
"include_sign": True,
|
||||
}
|
||||
dot_product_value = DecimalNumber(1.0, **dp_kwargs)
|
||||
dot_product_value.scale(sf)
|
||||
dot_product_value.next_to(brace, DOWN, sf * SMALL_BUFF)
|
||||
dot_product_value_update = ContinualChangingDecimal(
|
||||
dot_product_value,
|
||||
lambda a: np.dot(
|
||||
moving_step_vector.get_vector(),
|
||||
moving_diff_vector.get_vector(),
|
||||
),
|
||||
**dp_kwargs
|
||||
)
|
||||
|
||||
self.play(
|
||||
Write(dot_product),
|
||||
LaggedStart(MoveToTarget, copies)
|
||||
)
|
||||
self.remove(copies)
|
||||
self.play(FadeIn(div_text))
|
||||
self.play(ShowPassingFlashAround(
|
||||
div_text[1:3],
|
||||
surrounding_rectangle_config={"buff": sf * SMALL_BUFF}
|
||||
))
|
||||
self.add(BackgroundRectangle(dot_product_value))
|
||||
self.play(
|
||||
GrowFromCenter(brace),
|
||||
Write(dot_product_value),
|
||||
)
|
||||
self.add(dot_product_value_update)
|
||||
self.wait()
|
||||
|
||||
self.set_variables_as_attrs(
|
||||
div_text, dot_product,
|
||||
moving_step_vector,
|
||||
moving_diff_vector,
|
||||
dot_product_value,
|
||||
dot_product_value_update,
|
||||
brace,
|
||||
)
|
||||
|
||||
def show_circle_of_values(self):
|
||||
point = self.point
|
||||
moving_step_vector = self.moving_step_vector
|
||||
moving_diff_vector = self.moving_diff_vector
|
||||
|
||||
all_diff_vectors = VGroup()
|
||||
all_step_vectors = VGroup()
|
||||
# Loop around
|
||||
n_samples = 12
|
||||
angle = TAU / n_samples
|
||||
self.add_foreground_mobjects(self.step_words)
|
||||
for n in range(n_samples):
|
||||
self.play(
|
||||
Rotating(
|
||||
moving_step_vector,
|
||||
radians=angle,
|
||||
about_point=point,
|
||||
run_time=15.0 / n_samples,
|
||||
rate_func=None,
|
||||
)
|
||||
)
|
||||
step_vector_copy = moving_step_vector.copy()
|
||||
diff_vector_copy = moving_diff_vector.copy()
|
||||
diff_vector_copy.set_stroke(BLACK, 0.5)
|
||||
self.add(step_vector_copy, diff_vector_copy)
|
||||
all_step_vectors.add(step_vector_copy)
|
||||
all_diff_vectors.add(diff_vector_copy)
|
||||
self.remove(
|
||||
self.step_vector, self.diff_vector,
|
||||
self.moving_step_vector, self.moving_diff_vector,
|
||||
self.moving_diff_vector_update,
|
||||
self.dot_product_value_update
|
||||
)
|
||||
self.remove_foreground_mobjects(self.step_words)
|
||||
self.play(
|
||||
FadeOut(self.brace),
|
||||
FadeOut(self.dot_product_value),
|
||||
FadeOut(self.step_words),
|
||||
FadeOut(self.diff_words),
|
||||
)
|
||||
self.wait()
|
||||
|
||||
for s in 0.6, -0.6:
|
||||
for step, diff in zip(all_step_vectors, all_diff_vectors):
|
||||
diff.generate_target()
|
||||
diff.target.put_start_and_end_on(
|
||||
step.get_end(),
|
||||
step.get_end() + s * step.get_vector()
|
||||
)
|
||||
self.play(
|
||||
all_step_vectors.set_fill, {"opacity": 0.5},
|
||||
LaggedStart(
|
||||
MoveToTarget, all_diff_vectors,
|
||||
run_time=3
|
||||
),
|
||||
)
|
||||
self.wait()
|
||||
self.show_stream_lines(lambda p: s * (p - point))
|
||||
self.wait()
|
||||
|
||||
self.set_variables_as_attrs(
|
||||
all_step_vectors, all_diff_vectors,
|
||||
)
|
||||
|
||||
def switch_to_curl_words(self):
|
||||
sf = self.scale_factor
|
||||
div_text = self.div_text
|
||||
dot_product = self.dot_product
|
||||
|
||||
curl_text = self.get_operator_text("curl")
|
||||
cross_product = TextMobject(
|
||||
"(Step) $\\times$ (Difference)",
|
||||
tex_to_color_map={
|
||||
"Step": TEAL,
|
||||
"Difference": RED
|
||||
},
|
||||
arg_separator="",
|
||||
).scale(sf)
|
||||
cross_product.add_background_rectangle(opacity=1)
|
||||
|
||||
group = VGroup(curl_text, cross_product)
|
||||
group.arrange_submobjects(RIGHT, buff=sf * MED_SMALL_BUFF)
|
||||
group.next_to(self.camera_frame.get_top(), sf * DOWN)
|
||||
|
||||
self.play(
|
||||
dot_product.shift, sf * DOWN,
|
||||
dot_product.fade, 1,
|
||||
remover=True
|
||||
)
|
||||
self.play(FadeInAndShiftFromDirection(cross_product, sf * DOWN))
|
||||
self.play(
|
||||
div_text.shift, sf * DOWN,
|
||||
div_text.fade, 1,
|
||||
remover=True
|
||||
)
|
||||
self.play(FadeInAndShiftFromDirection(curl_text, sf * DOWN))
|
||||
self.wait()
|
||||
|
||||
def rotate_difference_vectors(self):
|
||||
point = self.point
|
||||
all_step_vectors = self.all_step_vectors
|
||||
all_diff_vectors = self.all_diff_vectors
|
||||
|
||||
for s in 0.6, -0.6:
|
||||
for step, diff in zip(all_step_vectors, all_diff_vectors):
|
||||
diff.generate_target()
|
||||
diff.target.put_start_and_end_on(
|
||||
step.get_end(),
|
||||
step.get_end() + s * rotate_vector(
|
||||
step.get_vector(),
|
||||
90 * DEGREES
|
||||
)
|
||||
)
|
||||
self.play(
|
||||
LaggedStart(
|
||||
MoveToTarget, all_diff_vectors,
|
||||
run_time=2
|
||||
),
|
||||
)
|
||||
self.wait()
|
||||
self.show_stream_lines(
|
||||
lambda p: s * rotate_vector((p - point), 90 * DEGREES)
|
||||
)
|
||||
self.wait()
|
||||
|
||||
self.set_variables_as_attrs(
|
||||
all_step_vectors, all_diff_vectors,
|
||||
)
|
||||
|
||||
# Helpers
|
||||
|
||||
def get_operator_text(self, operator):
|
||||
text = TextMobject(
|
||||
operator + "\\,",
|
||||
"$\\textbf{F}(x_0, y_0)\\,$",
|
||||
"corresponds to average of",
|
||||
arg_separator=""
|
||||
).scale(self.scale_factor)
|
||||
text.set_color_by_tex(operator, YELLOW)
|
||||
text.add_background_rectangle()
|
||||
return text
|
||||
|
||||
def show_stream_lines(self, func):
|
||||
point = self.point
|
||||
stream_lines = StreamLines(
|
||||
func,
|
||||
start_points_generator_config={
|
||||
"x_min": point[0] - 2,
|
||||
"x_max": point[0] + 2,
|
||||
"y_min": point[1] - 1,
|
||||
"y_max": point[1] + 1,
|
||||
"delta_x": 0.025,
|
||||
"delta_y": 0.025,
|
||||
},
|
||||
virtual_time=1,
|
||||
)
|
||||
random.shuffle(stream_lines.submobjects)
|
||||
self.play(LaggedStart(
|
||||
ShowPassingFlash,
|
||||
stream_lines,
|
||||
run_time=4,
|
||||
))
|
||||
|
||||
|
||||
class IncmpressibleAndIrrotational(Scene):
|
||||
def construct(self):
|
||||
div_0 = TextMobject("div$\\textbf{F} = 0$")
|
||||
curl_0 = TextMobject("curl$\\textbf{F}$ = 0")
|
||||
incompressible = TextMobject("Incompressible")
|
||||
irrotational = TextMobject("Irrotational")
|
||||
|
||||
for text in [div_0, curl_0, incompressible, irrotational]:
|
||||
text.add_background_rectangle(buff=SMALL_BUFF)
|
||||
|
||||
div_0.to_edge(UP)
|
||||
curl_0.next_to(div_0, DOWN, MED_LARGE_BUFF)
|
||||
|
||||
for op, word in (div_0, incompressible), (curl_0, irrotational):
|
||||
op.generate_target()
|
||||
group = VGroup(op.target, word)
|
||||
group.arrange_submobjects(RIGHT, buff=LARGE_BUFF)
|
||||
group.move_to(op)
|
||||
|
||||
self.play(FadeInFromDown(div_0))
|
||||
self.play(FadeInFromDown(curl_0))
|
||||
self.wait()
|
||||
self.play(
|
||||
MoveToTarget(div_0),
|
||||
FadeInFromDown(incompressible),
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
MoveToTarget(curl_0),
|
||||
FadeInFromDown(irrotational),
|
||||
)
|
||||
self.wait()
|
||||
|
||||
rect = SurroundingRectangle(VGroup(curl_0, irrotational))
|
||||
question = TextMobject("Does this actually happen?")
|
||||
question.next_to(rect, DOWN)
|
||||
question.match_color(rect)
|
||||
question.add_background_rectangle()
|
||||
|
||||
self.play(ShowCreation(rect))
|
||||
self.play(Write(question))
|
||||
self.wait()
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue