diff --git a/_2024/holograms/diffraction.py b/_2024/holograms/diffraction.py index 195e4eb..c58d44c 100644 --- a/_2024/holograms/diffraction.py +++ b/_2024/holograms/diffraction.py @@ -632,11 +632,7 @@ class LightExposingFilm(DiffractionGratingScene): self.wait(3) # Shift back - self.remove(ref_wave_label) - self.remove(exp_expr) - self.remove(film_label) - # shift_label = TexText(R"Shift back phase $\rightarrow$") - shift_label = TexText(R"Tiny change $\rightarrow$") + shift_label = TexText(R"Shift back phase $\rightarrow$") shift_label.rotate(PI / 2, DOWN) shift_label.set_backstroke(BLACK, 5) shift_label.move_to(5 * OUT + 1.25 * UP) @@ -1089,6 +1085,8 @@ class ExplainWaveVisualization(DiffractionGratingScene): class CreateZonePlate(DiffractionGratingScene): + samples = 4 + def construct(self): # Create object and reference wave frame = self.frame @@ -1122,20 +1120,24 @@ class CreateZonePlate(DiffractionGratingScene): ]) # Add film - plate_border = Rectangle(16, 9) - plate_border.set_fill(BLACK, 0) - plate_border.set_stroke(WHITE, 2) + plate = Rectangle(16, 9) + plate.set_height(4) + plate.set_stroke(WHITE, 1, 0.5).set_fill(BLACK, 0.0) + plate.set_shading(0.1, 0.1, 0) + plate.apply_depth_test() plate_body = Square3D() + plate_group = Group(plate_body, plate) + plate_body.set_color(BLACK, 0.9) - plate_body.replace(plate_border, stretch=True) - plate_body.set_shading(0.1, 0.1, 0) + plate_body.set_shape(plate.get_width(), plate.get_height()) + plate_body.move_to(plate.get_center() + 1e-2 * IN) + exposure = LightIntensity(DotCloud(get_all_sources())) exposure.set_decay_factor(0) exposure.set_wave_number(wave_number) - exposure.replace(plate_border, stretch=True).shift(1e-2 * OUT) + exposure.replace(plate, stretch=True).shift(1e-2 * OUT) exposure.set_color(WHITE, 0.85) - plate = Group(plate_border, plate_body) film = Group(plate, exposure) film.set_height(4) film.set_z(-2) @@ -1151,7 +1153,7 @@ class CreateZonePlate(DiffractionGratingScene): source_label.shift(0.25 * UL) source_label.set_backstroke(BLACK, 2) source_arrow = Arrow(source_label["Object"].get_bottom(), source_point.get_center(), buff=0.1) - source_arrow.set_perpendicular_to_camera(self.frame) + source_arrow.always.set_perpendicular_to_camera(self.frame) obj_point = TrueDot() obj_point.move_to(source_point) @@ -1160,8 +1162,9 @@ class CreateZonePlate(DiffractionGratingScene): obj_wave_label.next_to(source_point, IN, buff=0.1) obj_wave_label.set_backstroke(BLACK, 2) - frame.reorient(16, -9, 0, (-0.74, 0.32, -0.49), 7.08) - self.add(obj_wave, plate, film_label) + frame.reorient(41, -9, 0, (-0.72, 0.27, -0.49), 6.75) + self.add(plate_group, obj_wave, film_label) + plate_body.move_to(plate.get_center() + 1e-2 * IN) self.play( FadeIn(source_point), FadeIn(source_label), @@ -1184,7 +1187,7 @@ class CreateZonePlate(DiffractionGratingScene): ref_wave_label.set_backstroke(BLACK, 2) wave_fronts = Group( - plate_body.copy().set_color([BLUE, RED][z % 2], 0.15).shift(0.5 * z * OUT) + plate.copy().set_color([BLUE, RED][z % 2], 0.15).shift(0.5 * z * OUT) for z in range(4, 16) ) for front in wave_fronts: @@ -1322,11 +1325,11 @@ class CreateZonePlate(DiffractionGratingScene): ) # Look off center - exposure.replace(plate_body, stretch=True) - exposure.set_shape(0.5 * plate_body.get_width(), 0.25) - exposure.move_to(plate_body.get_center(), LEFT).shift(1e-2 * OUT) + exposure.replace(plate, stretch=True) + exposure.set_shape(0.5 * plate.get_width(), 0.25) + exposure.move_to(plate.get_center(), LEFT).shift(1e-2 * OUT) full_exposure = exposure.copy() - full_exposure.replace(plate_body, stretch=True) + full_exposure.replace(plate, stretch=True) full_exposure.shift(2e-2 * OUT) exposure.save_state() exposure.stretch(0, 0, about_edge=LEFT) @@ -1339,7 +1342,7 @@ class CreateZonePlate(DiffractionGratingScene): ).shift(O_point - m[0].get_center()) ) - trg_point = VectorizedPoint(plate_body.get_center()) + trg_point = VectorizedPoint(plate.get_center()) obj_line.add_updater(lambda m: m.put_start_and_end_on(source_point.get_center(), trg_point.get_center())) ref_line.add_updater(lambda m: m.move_to(trg_point.get_center() + 0.02 * RIGHT, IN)) @@ -1360,7 +1363,7 @@ class CreateZonePlate(DiffractionGratingScene): # Look to halfwavelength point trg_x = 0.9 - mid_line = Line(source_point.get_center(), plate_body.get_center()) + mid_line = Line(source_point.get_center(), plate.get_center()) mid_line.set_stroke(TEAL, 2) mid_line_label = Tex("D", font_size=30).rotate(PI / 2, LEFT) mid_line_label.next_to(mid_line, LEFT) @@ -1373,7 +1376,7 @@ class CreateZonePlate(DiffractionGratingScene): FadeOut(ref_line), FadeOut(ref_graph), frame.animate.reorient(0, -62, 0, (-0.27, -1.26, -1.17), 7.38), - trg_point.animate.move_to(plate_body.get_center() + trg_x * RIGHT), + trg_point.animate.move_to(plate.get_center() + trg_x * RIGHT), run_time=3 ) d_line_label.next_to(obj_line.get_center(), RIGHT, buff=SMALL_BUFF) @@ -1420,7 +1423,7 @@ class CreateZonePlate(DiffractionGratingScene): self.wait(2) # Grow rings fully - exposure.replace(plate_body, stretch=True).shift(0.01 * OUT) + exposure.replace(plate, stretch=True).shift(0.01 * OUT) self.add(exposure, round_exposure) self.play( @@ -1539,10 +1542,10 @@ class CreateZonePlate(DiffractionGratingScene): ) self.wait(4) - # Go to othe side + # Go to other side frame.reorient(-171, -18, 0, (0.12, -0.21, -1.33), 9.31) self.remove(film) - self.add(exposure, plate_border) + self.add(exposure, plate) self.play( frame.animate.reorient(0, -16, 0, (-3.06, -0.18, -3.19), 1.49), run_time=10, @@ -1599,23 +1602,23 @@ class ShowEffectOfChangedReferenceAngle(InteractiveScene): plate_border = Rectangle(16, 9) plate_border.set_fill(BLACK, 0) plate_border.set_stroke(WHITE, 2) - plate_body = Square3D() - plate_body.set_color(BLACK, 0.9) - plate_body.replace(plate_border, stretch=True) - plate_body.set_shading(0.1, 0.1, 0) + plate = Square3D() + plate.set_color(BLACK, 0.9) + plate.replace(plate_border, stretch=True) + plate.set_shading(0.1, 0.1, 0) exposure = LightIntensity(source_points) exposure.set_decay_factor(0) exposure.set_wave_number(wave_number) exposure.replace(plate_border, stretch=True).shift(1e-2 * OUT) exposure.set_color(WHITE, 0.85) - plate = Group(plate_border, plate_body) - film = Group(plate, exposure) + plate_group = Group(plate_border, plate) + film = Group(plate_group, exposure) film.set_height(4) film.set_z(-2) film_label = Text("Film") - film_label.next_to(plate, UP) + film_label.next_to(plate_group, UP) film_label.set_backstroke(BLACK, 3) film_label.set_z_index(1) @@ -3724,6 +3727,24 @@ class SuperpositionOfPoints(InteractiveScene): ) self.wait(3) + # Transform point into film + frame.clear_updaters() + frame.reorient(111, -13, 0, (-0.54, 0.04, -1.71), 5.72) + pre_dots = dot_cloud.copy() + pre_dots.set_points(dot_cloud.get_points()[:len(sheet_dots.get_points())]) + + self.play( + TransformFromCopy(pre_dots, sheet_dots, time_span=(2, 8)), + frame.animate.reorient(17, -19, 0, (0.82, 0.57, -3.07), 7.99), + run_time=12 + ) + self.play( + dot_cloud.animate.shift(2 * IN), + UpdateFromFunc(sheet_dots, lambda m: self.color_sheet_by_exposure(m, dot_cloud.get_points()[:1000], wave_number=32)), + run_time=3, + ) + self.wait() + def color_sheet_by_exposure(self, sheet_dots, point_sources, wave_number=16, opacity=0.5): centers = sheet_dots.get_points() diffs = centers[:, np.newaxis, :] - point_sources[np.newaxis, :, :] @@ -4026,7 +4047,7 @@ class ComplexWaves(InteractiveScene): lhs = Text("Film opacity = ") lhs.move_to(amp_expr, LEFT) lhs.set_color(GREY_B) - new_amp_expr = Tex(R"|R + O|^2") + new_amp_expr = Tex(R"c|R + O|^2") new_amp_expr.next_to(lhs, RIGHT) self.play( @@ -4056,6 +4077,75 @@ class ComplexWaves(InteractiveScene): return result +class StateOnA2DScreen(InteractiveScene): + def construct(self): + # Add screen + frame = self.frame + self.set_floor_plane("xz") + + screen = ScreenRectangle() + screen.set_height(6) + screen.set_stroke(WHITE, 1) + + source_points = DotCloud(np.random.random((10, 3))) + source_points.set_width(8) + source_points.move_to(screen, OUT) + wave2d = LightWaveSlice(source_points) + wave2d.replace(screen, stretch=True) + wave2d.set_wave_number(4) + wave2d.set_frequency(1) + wave2d.set_max_amp(4) + wave2d.set_decay_factor(0) + + axes = ThreeDAxes((-5, 5), (-5, 5), (-5, 5)) + + self.add(axes) + self.add(screen) + self.add(wave2d) + self.wait(4) + + # Zoom out to 3d waves + wave3d = Group( + # wave2d.copy().rotate(PI / 2, RIGHT).stretch(10, 2).move_to(ORIGIN, IN) + ) + n_slices = 3 + for x in np.linspace(-5, 5, n_slices): + wave_slice = wave2d.copy() + wave_slice.scale(20) + wave_slice.rotate(PI / 2, UP) + wave_slice.move_to(ORIGIN, IN) + wave_slice.set_x(x) + wave_slice.set_opacity(1.0 / n_slices) + wave3d.add(wave_slice) + + for wave in wave3d: + wave.set_opacity(1) + wave.set_max_amp(10) + + # wave3d[n_slices // 2].set_opacity(0.75) + # wave3d.set_opacity(0.1) + # wave3d.save_state() + # wave3d.stretch(0, dim=2, about_point=ORIGIN) + + self.play( + frame.animate.reorient(101, -1, 0, (-0.53, 0.13, 7.82), 13.40), + FadeIn(wave3d, time_span=(3, 8)), + run_time=8, + ) + + # Linger and collapse + self.wait(4) + self.play( + LaggedStart(*( + wave.animate.match_points(wave2d).set_opacity(1).shift(1e-2 * IN) + for wave in wave3d + ), lag_ratio=0), + frame.animate.reorient(25, -6, 0, (0.18, 0.29, 0.15), 9.15).set_anim_args(time_span=(1, 4)), + run_time=4 + ) + self.wait(8) + + ## Old ## class PointSourceDiffractionPattern(InteractiveScene): diff --git a/_2024/holograms/supplements.py b/_2024/holograms/supplements.py index 5e64530..1cd3f8e 100644 --- a/_2024/holograms/supplements.py +++ b/_2024/holograms/supplements.py @@ -348,11 +348,9 @@ class Outline(InteractiveScene): class GoalOfRediscovery(TeacherStudentsScene): def construct(self): # Test - for pi in self.pi_creatures: - pi.body.insert_n_curves(100) morty = self.teacher self.play( - self.change_students("pondering", "confused", "erm", look_at=self.screen), + self.change_students("pondering", "confused", "maybe", look_at=self.screen), morty.change("guilty"), ) self.wait(2) @@ -1314,6 +1312,110 @@ class ModeledAs2D(InteractiveScene): self.wait() +class ThinkingAboutRediscovery(InteractiveScene): + def construct(self): + # Test + randy = Randolph() + randy.body.insert_n_curves(100) + randy.to_corner(DL) + bubble = ThoughtBubble(filler_shape=(5, 2)) + bubble.pin_to(randy) + bubble = bubble[0] + bubble.set_fill(opacity=0) + + rect = FullScreenRectangle().set_fill(BLACK, 1) + rect.append_points([rect.get_points()[-1], *bubble[-1].get_points()]) + self.add(rect, randy) + + self.play( + randy.change('pondering'), + Write(bubble, stroke_color=WHITE, lag_ratio=0.2) + ) + self.play(Blink(randy)) + self.wait(2) + self.play(randy.change('thinking', bubble.get_top())) + self.play(Blink(randy)) + self.play(randy.change('tease', bubble.get_top())) + for _ in range(2): + self.play(Blink(randy)) + self.wait(2) + + +class IntroduceFormalSection(TeacherStudentsScene): + def construct(self): + # Test + morty = self.teacher + stds = self.students + + self.play(LaggedStart( + stds[0].change("sassy", morty.eyes), + stds[1].says("Okay but really, why\ndoes it work?", look_at=morty.eyes), + stds[2].change("angry", look_at=morty.eyes), + morty.change("guilty"), + )) + self.wait(2) + self.play(LaggedStart( + morty.change("tease"), + stds[0].change("well"), + stds[1].debubble(), + stds[2].change("hesitant"), + lag_ratio=0.5 + )) + self.wait(2) + + # Show complex plane + plane = ComplexPlane((-3, 3), (-3, 3)) + plane.faded_lines.set_stroke(BLUE_E, 1, 0.5) + plane.axes.set_stroke(width=1) + plane.background_lines.set_stroke(width=1) + plane.set_width(3) + plane.next_to(self.hold_up_spot, UP) + + a, b = (2, 1.5) + z = complex(a, b) + z_dot = GlowDot(plane.n2p(0), color=WHITE) + z_dot.set_z_index(1) + h_line = Line(plane.n2p(0), plane.n2p(a)) + v_line = Line(plane.n2p(a), plane.n2p(z)) + h_line.set_stroke(YELLOW, 3) + v_line.set_stroke(RED, 3) + a_label = Tex(R"a", font_size=24) + a_label.match_color(h_line) + a_label.next_to(h_line, DOWN, buff=0.1) + b_label = Tex(R"bi", font_size=24) + b_label.match_color(v_line) + b_label.next_to(v_line, RIGHT, buff=0.1) + z_label = Tex(R"a + bi", font_size=24) + z_label.next_to(v_line.get_end(), UR, SMALL_BUFF) + VGroup(a_label, b_label, z_label).set_backstroke(BLACK, 3) + + self.play( + morty.change("raise_right_hand", plane), + self.change_students(*3 * ["pondering"], look_at=plane), + FadeIn(plane, UP), + ) + self.play( + ShowCreation(h_line), + FadeIn(a_label, 0.5 * RIGHT), + z_dot.animate.move_to(plane.n2p(a)), + ) + self.play( + ShowCreation(v_line), + FadeIn(b_label, 0.5 * UP), + z_dot.animate.move_to(plane.n2p(z)), + ) + self.play( + TransformMatchingShapes(VGroup(a_label, b_label).copy(), z_label) + ) + self.play(self.change_students("erm", "thinking", "well", look_at=plane)) + self.wait(2) + + +class HoldUpEquation(InteractiveScene): + def construct(self): + pass + + class GaborQuote(InteractiveScene): def construct(self): # Test @@ -1331,6 +1433,19 @@ class GaborQuote(InteractiveScene): self.wait() +class GaborQuote2(InteractiveScene): + def construct(self): + # Test + quote = TexText(R""" + ``In holography, nature\\ + is on the inventor's side'' + """, font_size=60, alignment="") + quote.to_edge(RIGHT) + + self.play(Write(quote), run_time=2, lag_ratio=0.1) + self.wait() + + class ComplexConjugateFact(InteractiveScene): def construct(self): # Show conjugate @@ -1397,6 +1512,49 @@ class ComplexConjugateFact(InteractiveScene): self.wait() +class PrepareComplexAlgebra(InteractiveScene): + def construct(self): + # Test + lines = VGroup( + Tex(R"R \cdot (1 - \text{Opacity})"), + Tex(R"R \cdot (1 - c|R + O|^2)"), + Tex(R"R - c R \cdot |R + O|^2"), + ) + lines.arrange(DOWN, buff=0.75) + lines.to_edge(UP) + + label = Text("Wave beyond\nthe film") + arrow = Vector(LEFT) + arrow.next_to(lines[0], RIGHT) + label.next_to(arrow, RIGHT) + + rect = SurroundingRectangle(lines[2][R"R \cdot |R + O|^2"], buff=0.05) + rect.set_stroke(TEAL, 2) + + self.play( + FadeIn(label, lag_ratio=0.1), + GrowArrow(arrow), + FadeIn(lines[0], LEFT), + ) + self.wait() + self.play( + TransformMatchingStrings(lines[0].copy(), lines[1]), + run_time=2 + ) + self.wait() + self.play( + TransformMatchingStrings(lines[1].copy(), lines[2]), + run_time=2 + ) + self.wait() + self.play( + ShowCreation(rect), + lines[:2].animate.set_opacity(0.5), + lines[2][R"R - c"].animate.set_opacity(0.5), + ) + self.wait() + + class ComplexAlgebra(InteractiveScene): def construct(self): # Add first lines @@ -1410,7 +1568,7 @@ class ComplexAlgebra(InteractiveScene): lines.arrange(DOWN, buff=LARGE_BUFF) lines.to_edge(UP) - label = Text("Wave beyond\nthe film") + label = Text("Part of the wave\nbeyond the film", font_size=36) arrow = Vector(LEFT) arrow.next_to(lines[0], RIGHT) label.next_to(arrow, RIGHT) @@ -1618,6 +1776,49 @@ class ComplexAlgebra(InteractiveScene): ).set_stroke(WHITE, 2) +class PlaneAfterFilm(InteractiveScene): + def construct(self): + # Test + image = ImageMobject("FilmFromBehind") + image.set_height(FRAME_HEIGHT) + image.set_height(FRAME_HEIGHT) + image.fix_in_frame() + # self.add(image) + + rect = Polygon( + (2.56, -0.12, 0.0), + (5.69, -2.51, 0.0), + (6.25, 1.31, 0.0), + (2.72, 2.62, 0.0), + ) + rect.set_fill(BLACK, 0.75) + rect.set_stroke(BLUE, 10) + rect.fix_in_frame() + words = Text("True on this\n2D Plane") + + self.set_floor_plane("xz") + self.frame.reorient(73, -24, 0, (-1.53, -0.68, 4.14), 9.19) + + self.play( + DrawBorderThenFill(rect), + FadeIn(words), + ) + self.wait() + + +class LookingAtScreen(TeacherStudentsScene): + def construct(self): + self.play( + self.change_students("confused", "pondering", "maybe", look_at=self.screen), + self.teacher.change("well") + ) + self.wait(5) + + +class EndScreen(PatreonEndScreen): + pass + + # Old stubs class DoubleSlitSupplementaryGraphs(InteractiveScene):