diff --git a/active_projects/shadows.py b/active_projects/shadows.py index 36bc41aa..cef60ae9 100644 --- a/active_projects/shadows.py +++ b/active_projects/shadows.py @@ -5,8 +5,13 @@ from big_ol_pile_of_manim_imports import * def get_shadow(mobject, opacity=0.5): result = mobject.deepcopy() result.apply_function(lambda p: [p[0], p[1], 0]) - result.set_fill(BLACK, opacity=opacity) - result.set_stroke(BLACK, 0) + color = interpolate_color( + mobject.get_fill_color(), BLACK, + mobject.get_fill_opacity() + ) + # color = BLACK + result.set_fill(color, opacity=opacity) + result.set_stroke(BLACK, 0.5, opacity=opacity) result.set_shade_in_3d(False) return result @@ -57,11 +62,6 @@ class ShowShadows(ThreeDScene): def setup(self): self.add_plane() - self.set_camera_orientation( - phi=60 * DEGREES, - theta=-90 * DEGREES, - ) - # self.begin_ambient_camera_rotation(0.02) self.setup_orientation_trackers() self.setup_object_and_shadow() self.add_shadow_area_label() @@ -73,8 +73,9 @@ class ShowShadows(ThreeDScene): height=24.2, stroke_width=0, fill_color=WHITE, - fill_opacity=0.5, + fill_opacity=0.35, ) + plane.set_sheen(0.2, DR) grid = NumberPlane( color=LIGHT_GREY, secondary_color=DARK_GREY, @@ -103,12 +104,23 @@ class ShowShadows(ThreeDScene): label = VGroup(text, decimal) label.arrange_submobjects(RIGHT) label.scale(1.5) - label.move_to(self.area_label_center) + label.move_to(self.area_label_center - decimal.get_center()) self.shadow_area_label = label + self.shadow_area_decimal = decimal + + # def update_decimal(decimal): + # # decimal.set_value(get_area(self.shadow)) + # self.add_fixed_in_frame_mobjects(decimal) + + # decimal.add_updater(update_decimal) continual_update = ContinualChangingDecimal( - decimal, lambda a: get_area(self.shadow) + decimal, + lambda a: get_area(self.shadow), + position_update_func=lambda d: self.add_fixed_in_frame_mobjects(d) ) + # self.add_fixed_orientation_mobjects(label) + self.add_fixed_in_frame_mobjects(label) self.add(label) self.add(continual_update) @@ -118,21 +130,40 @@ class ShowShadows(ThreeDScene): label = VGroup(text, decimal) label.arrange_submobjects(RIGHT) label.scale(1.25) - label.next_to(self.obj3d, RIGHT, MED_LARGE_BUFF) + label.set_fill(YELLOW) + label.set_background_stroke(width=3) + label.next_to(self.obj3d, RIGHT, LARGE_BUFF) + label.shift(MED_LARGE_BUFF * IN) self.surface_area_label = label self.add_fixed_orientation_mobjects(label) def construct(self): + # Show creation obj3d = self.obj3d.copy() obj3d.clear_updaters() temp_shadow = updating_mobject_from_func(lambda: get_shadow(obj3d)) self.add(temp_shadow) - self.play(LaggedStart(DrawBorderThenFill, obj3d)) + self.move_camera( + phi=60 * DEGREES, + theta=-120 * DEGREES, + added_anims=[ + LaggedStart(DrawBorderThenFill, obj3d) + ], + run_time=2 + ) + self.begin_ambient_camera_rotation(0.01) self.remove(obj3d, temp_shadow) + + average_label = self.get_average_label() + # Reorient self.add(self.obj3d, self.shadow) for n in range(self.num_reorientations): self.randomly_reorient() - self.wait() + if n == 3: + self.add_fixed_in_frame_mobjects(average_label) + self.play(Write(average_label, run_time=2)) + else: + self.wait() def randomly_reorient(self, run_time=3): a, b, c = TAU * np.random.random(3) @@ -166,11 +197,32 @@ class ShowShadows(ThreeDScene): obj3d.rotate(angle, vect, about_point=center) return obj3d + def get_average_label(self): + rect = SurroundingRectangle( + self.shadow_area_decimal, + buff=SMALL_BUFF, + color=RED, + ) + words = TextMobject( + "Average", "=", + "$\\frac{\\text{Surface area}}{4}$" + ) + words.scale(1.5) + words[0].match_color(rect) + words[2].set_color(self.surface_area_label[0].get_fill_color()) + words.set_background_stroke(width=3) + words.next_to( + rect, DOWN, + index_of_submobject_to_align=0, + ) + # words.shift(MED_LARGE_BUFF * LEFT) + return VGroup(rect, words) + class ShowInfinitelyFarLightSource(ShowShadows): CONFIG = { "num_reorientations": 1, - "camera_center": [0, 0, 1] + "camera_center": [0, 0, 1], } def construct(self): @@ -193,6 +245,7 @@ class ShowInfinitelyFarLightSource(ShowShadows): def move_light_around(self): light = self.light + self.add_foreground_mobjects(self.shadow_area_label) self.play( light.move_to, 5 * OUT + DOWN, run_time=3 @@ -209,9 +262,27 @@ class ShowInfinitelyFarLightSource(ShowShadows): def show_vertical_lines(self): lines = self.get_vertical_lines() + obj3d = self.obj3d + shadow = self.shadow + target_obj3d = obj3d.copy() + target_obj3d.become(shadow) + target_obj3d.match_style(obj3d) + target_obj3d.set_shade_in_3d(False) + source_obj3d = obj3d.copy() + source_obj3d.set_shade_in_3d(False) + source_obj3d.fade(1) + self.play(LaggedStart(ShowCreation, lines)) - lines.add_updater(lambda m: m.become(self.get_vertical_lines())) self.wait() + self.add(source_obj3d, lines) + self.play( + ReplacementTransform(source_obj3d, target_obj3d), + run_time=2 + ) + self.add(target_obj3d, lines) + self.play(FadeOut(target_obj3d),) + self.wait() + lines.add_updater(lambda m: m.become(self.get_vertical_lines())) for x in range(5): self.randomly_reorient() @@ -220,20 +291,21 @@ class ShowInfinitelyFarLightSource(ShowShadows): light_source = self.camera.light_source obj3d = self.obj3d center = obj3d.get_center() - right = center + RIGHT - up = center + UP def update(shadow): lsp = light_source.get_center() - proj_center, proj_right, proj_up = [ - get_xy_plane_projection_point(lsp, point) - for point in [center, right, up] - ] - matrix = np.array([ - proj_right - proj_center, - proj_up - proj_center - ]).T - shadow.apply_matrix(matrix) + proj_center = get_xy_plane_projection_point(lsp, center) + c_to_lsp = lsp - center + unit_c_to_lsp = normalize(c_to_lsp) + rotation = rotation_matrix( + angle=np.arccos(np.dot(unit_c_to_lsp, OUT)), + axis=normalize(np.cross(unit_c_to_lsp, OUT)) + ) + new_shadow = get_shadow( + self.obj3d.copy().apply_matrix(rotation) + ) + shadow.become(new_shadow) + shadow.scale(get_norm(lsp) / get_norm(c_to_lsp)) shadow.move_to(proj_center) return shadow shadow.add_updater(update) @@ -254,8 +326,8 @@ class ShowInfinitelyFarLightSource(ShowShadows): def get_vertical_lines(self): shadow = self.shadow points = get_boundary_points(shadow, 10) - half_points = [(p1 + p2) / 2 for p1, p2 in adjacent_pairs(points)] - points = np.append(points, half_points, axis=0) + # half_points = [(p1 + p2) / 2 for p1, p2 in adjacent_pairs(points)] + # points = np.append(points, half_points, axis=0) light_source = self.light.get_center() lines = VGroup(*[ DashedLine(light_source, point) @@ -271,7 +343,8 @@ class ShowInfinitelyFarLightSource(ShowShadows): class CylinderShadows(ShowShadows): CONFIG = { - "surface_area": 2 * PI + 2 * PI * 2 + "surface_area": 2 * PI + 2 * PI * 2, + "area_label_center": [0, -2, 0], } def get_object(self): @@ -328,3 +401,11 @@ class PrismShadows(ShowShadows): prism.set_fill(PINK, 0.8) prism.set_stroke(WHITE, 1) return prism + + +class TheseFourPiAreSquare(PiCreatureScene): + def construct(self): + pass + + def create_pi_creatures(self): + pass