diff --git a/camera/camera.py b/camera/camera.py index 4dd1e5ff..645d608b 100644 --- a/camera/camera.py +++ b/camera/camera.py @@ -30,9 +30,10 @@ class Camera(object): CONFIG = { "background_image": None, "pixel_shape": (DEFAULT_PIXEL_HEIGHT, DEFAULT_PIXEL_WIDTH), - # Note: frame_shape will be resized to match pixel_shape - "frame_shape": (FRAME_HEIGHT, FRAME_WIDTH), - "space_center": ORIGIN, + # Note: frame height and width will be resized to match pixel_shape + "frame_height": FRAME_HEIGHT, + "frame_width": FRAME_WIDTH, + "frame_center": ORIGIN, "background_color": BLACK, "background_opacity": 0, # Points in vectorized mobjects with norm greater @@ -67,21 +68,41 @@ class Camera(object): self.resize_frame_shape() self.reset() + def get_frame_height(self): + return self.frame_height + + def get_frame_width(self): + return self.frame_width + + def get_frame_center(self): + return self.frame_center + + def set_frame_height(self, frame_height): + self.frame_height = frame_height + + def set_frame_width(self, frame_width): + self.frame_width = frame_width + + def set_frame_center(self, frame_center): + self.frame_center = frame_center + def resize_frame_shape(self, fixed_dimension=0): """ Changes frame_shape to match the aspect ratio of pixel_shape, where fixed_dimension determines - whether frame_shape[0] (height) or frame_shape[1] (width) + whether frame_height or frame_width remains fixed while the other changes accordingly. """ - frame_height, frame_width = self.frame_shape pixel_height, pixel_width = self.pixel_shape + frame_height = self.get_frame_height() + frame_width = self.get_frame_width() aspect_ratio = fdiv(pixel_width, pixel_height) if fixed_dimension == 0: frame_height = frame_width / aspect_ratio else: frame_width = aspect_ratio * frame_height - self.frame_shape = (frame_height, frame_width) + self.set_frame_height(frame_height) + self.set_frame_width(frame_width) def init_background(self): if self.background_image is not None: @@ -455,15 +476,16 @@ class Camera(object): return points def points_to_pixel_coords(self, points): - shifted_points = points - self.space_center + shifted_points = points - self.get_frame_center() result = np.zeros((len(points), 2)) - ph, pw = self.pixel_shape - sh, sw = self.frame_shape - width_mult = pw / sw - width_add = pw / 2 - height_mult = ph / sh - height_add = ph / 2 + pixel_height, pixel_width = self.pixel_shape + frame_height = self.get_frame_height() + frame_width = self.get_frame_width() + width_mult = pixel_width / frame_width + width_add = pixel_width / 2 + height_mult = pixel_height / frame_height + height_add = pixel_height / 2 # Flip on y-axis as you go height_mult *= -1 @@ -499,7 +521,10 @@ class Camera(object): def get_coords_of_all_pixels(self): # These are in x, y order, to help me keep things straight - full_space_dims = np.array(self.frame_shape)[::-1] + full_space_dims = np.array([ + self.get_frame_width(), + self.get_frame_height() + ]) full_pixel_dims = np.array(self.pixel_shape)[::-1] # These are addressed in the same y, x order as in pixel_array, but the values in them diff --git a/camera/mapping_camera.py b/camera/mapping_camera.py index cc283ccc..9efdea31 100644 --- a/camera/mapping_camera.py +++ b/camera/mapping_camera.py @@ -43,6 +43,7 @@ class MappingCamera(Camera): # TODO: Add optional separator borders between cameras (or perhaps peel this off into a # CameraPlusOverlay class) +# TODO, the classes below should likely be deleted class OldMultiCamera(Camera): def __init__(self, *cameras_with_start_positions, **kwargs): diff --git a/camera/moving_camera.py b/camera/moving_camera.py index 053a7ebb..16585f54 100644 --- a/camera/moving_camera.py +++ b/camera/moving_camera.py @@ -34,21 +34,40 @@ class MovingCamera(Camera): self.frame = frame Camera.__init__(self, **kwargs) + # TODO, make these work for a rotated frame + def get_frame_height(self): + return self.frame.get_height() + + def get_frame_width(self): + return self.frame.get_width() + + def get_frame_center(self): + return self.frame.get_center() + + def set_frame_height(self, frame_height): + self.frame.stretch_to_fit_height(frame_height) + + def set_frame_width(self, frame_width): + self.frame.stretch_to_fit_width(frame_width) + + def set_frame_center(self, frame_center): + self.frame.move_to(frame_center) + def capture_mobjects(self, mobjects, **kwargs): - self.reset_space_center() - self.realign_frame_shape() + # self.reset_frame_center() + # self.realign_frame_shape() Camera.capture_mobjects(self, mobjects, **kwargs) - def reset_space_center(self): - self.space_center = self.frame.get_center() + # def reset_frame_center(self): + # self.frame_center = self.frame.get_center() - def realign_frame_shape(self): - height, width = self.frame_shape - if self.fixed_dimension == 0: - self.frame_shape = (height, self.frame.get_width()) - else: - self.frame_shape = (self.frame.get_height(), width) - self.resize_frame_shape(fixed_dimension=self.fixed_dimension) + # def realign_frame_shape(self): + # height, width = self.frame_shape + # if self.fixed_dimension == 0: + # self.frame_shape = (height, self.frame.get_width()) + # else: + # self.frame_shape = (self.frame.get_height(), width) + # self.resize_frame_shape(fixed_dimension=self.fixed_dimension) def get_mobjects_indicating_movement(self): """ diff --git a/camera/multi_camera.py b/camera/multi_camera.py index ee0a2c12..af9ccd9a 100644 --- a/camera/multi_camera.py +++ b/camera/multi_camera.py @@ -25,15 +25,14 @@ class MultiCamera(MovingCamera): def update_sub_cameras(self): """ Reshape sub_camera pixel_arrays """ for imfc in self.image_mobjects_from_cameras: - frame_height, frame_width = self.frame_shape pixel_height, pixel_width = self.get_pixel_array().shape[:2] imfc.camera.frame_shape = ( imfc.camera.frame.get_height(), imfc.camera.frame.get_width(), ) imfc.camera.reset_pixel_shape(( - int(pixel_height * imfc.get_height() / frame_height), - int(pixel_width * imfc.get_width() / frame_width), + int(pixel_height * imfc.get_height() / self.get_frame_height()), + int(pixel_width * imfc.get_width() / self.get_frame_width()), )) def reset(self): diff --git a/camera/three_d_camera.py b/camera/three_d_camera.py index 84ddece8..55cd1967 100644 --- a/camera/three_d_camera.py +++ b/camera/three_d_camera.py @@ -49,7 +49,7 @@ class ThreeDCamera(CameraWithPerspective): self.rotation_mobject = VectorizedPoint() # moving_center lives in the x-y-z space # It representes the center of rotation - self.moving_center = VectorizedPoint(self.space_center) + self.moving_center = VectorizedPoint(self.frame_center) self.set_position(self.phi, self.theta, self.distance) def modified_rgb(self, vmobject, rgb): @@ -163,7 +163,7 @@ class ThreeDCamera(CameraWithPerspective): center_of_rotation = self.get_center_of_rotation( center_x, center_y, center_z) self.moving_center.move_to(center_of_rotation) - self.space_center = self.moving_center.points[0] + self.frame_center = self.moving_center.points[0] def get_view_transformation_matrix(self): return (self.default_distance / self.get_distance()) * np.dot( @@ -174,6 +174,6 @@ class ThreeDCamera(CameraWithPerspective): def points_to_pixel_coords(self, points): matrix = self.get_view_transformation_matrix() new_points = np.dot(points, matrix.T) - self.space_center = self.moving_center.points[0] + self.frame_center = self.moving_center.points[0] return Camera.points_to_pixel_coords(self, new_points) diff --git a/mobject/mobject.py b/mobject/mobject.py index 8283c345..c6364fa3 100644 --- a/mobject/mobject.py +++ b/mobject/mobject.py @@ -199,6 +199,15 @@ class Mobject(Container): ) return self + def apply_function_to_position(self, function): + self.move_to(function(self.get_center())) + return self + + def apply_function_to_submobject_positions(self, function): + for submob in self.submobjects: + submob.apply_function_to_position(function) + return self + def apply_matrix(self, matrix, **kwargs): # Default to applying matrix about the origin, not mobjects center if len(kwargs) == 0: diff --git a/old_projects/basel/basel.py b/old_projects/basel/basel.py index 69809107..c3301a43 100644 --- a/old_projects/basel/basel.py +++ b/old_projects/basel/basel.py @@ -2056,7 +2056,7 @@ class IPTScene1(PiCreatureScene): # use the following for the zoomed inset if show_detail: self.camera.frame_shape = (0.02 * FRAME_HEIGHT, 0.02 * FRAME_WIDTH) - self.camera.space_center = C + self.camera.frame_center = C SCREEN_SCALE = 0.01 SCREEN_THICKNESS = 0.02 diff --git a/scene/zoomed_scene.py b/scene/zoomed_scene.py index 00ac598b..579616ac 100644 --- a/scene/zoomed_scene.py +++ b/scene/zoomed_scene.py @@ -7,11 +7,12 @@ from mobject.types.image_mobject import ImageMobjectFromCamera from utils.simple_functions import fdiv from constants import * - +from animation.transform import ApplyMethod # Note, any scenes from old videos using ZoomedScene will almost certainly # break, as it was restructured. + class ZoomedScene(MovingCameraScene): CONFIG = { "camera_class": MultiCamera, @@ -56,33 +57,36 @@ class ZoomedScene(MovingCameraScene): self.zoomed_camera = zoomed_camera self.zoomed_display = zoomed_display - def activate_zooming(self, animate=False, run_times=[2, 1]): - zoomed_camera = self.zoomed_camera - zoomed_display = self.zoomed_display - + def activate_zooming(self, animate=False): self.zoom_activated = True - self.camera.add_image_mobject_from_camera(zoomed_display) - - to_add = [zoomed_camera.frame, zoomed_display] + self.camera.add_image_mobject_from_camera(self.zoomed_display) if animate: - zoomed_display.save_state(use_deepcopy=True) - zoomed_display.replace(zoomed_camera.frame) + self.play(self.get_zoom_in_animation()) + self.play(self.get_zoomed_display_pop_out_animation()) + self.add_foreground_mobjects( + self.zoomed_camera.frame, + self.zoomed_display, + ) - full_frame_height, full_frame_width = self.camera.frame_shape - zoomed_camera.frame.save_state() - zoomed_camera.frame.stretch_to_fit_width(full_frame_width) - zoomed_camera.frame.stretch_to_fit_height(full_frame_height) - zoomed_camera.frame.center() - zoomed_camera.frame.set_stroke(width=0) + def get_zoom_in_animation(self, run_time=2, **kwargs): + frame = self.zoomed_camera.frame + full_frame_height = self.camera.get_frame_height() + full_frame_width = self.camera.get_frame_width() + frame.save_state() + frame.stretch_to_fit_width(full_frame_width) + frame.stretch_to_fit_height(full_frame_height) + frame.center() + frame.set_stroke(width=0) + return ApplyMethod(frame.restore, run_time=run_time, **kwargs) - for mover, run_time in zip(to_add, run_times): - self.add_foreground_mobject(mover) - self.play(mover.restore, run_time=run_time) - else: - self.add_foreground_mobjects(*to_add) + def get_zoomed_display_pop_out_animation(self, **kwargs): + display = self.zoomed_display + display.save_state(use_deepcopy=True) + display.replace(self.zoomed_camera.frame, stretch=True) + return ApplyMethod(display.restore) def get_zoom_factor(self): return fdiv( - self.zoomed_camera.frame.get_width(), - self.zoomed_display.get_width() + self.zoomed_camera.frame.get_height(), + self.zoomed_display.get_height() )