From 40d0fcc974ba0bae912a51d15b815eed3c91489a Mon Sep 17 00:00:00 2001 From: frozar Date: Fri, 2 Feb 2018 10:34:08 +0100 Subject: [PATCH 1/3] [3D CAMERA] New feature: give the possibility to change the center of rotation. --- topics/three_dimensions.py | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/topics/three_dimensions.py b/topics/three_dimensions.py index b0c18645..809979f5 100644 --- a/topics/three_dimensions.py +++ b/topics/three_dimensions.py @@ -36,8 +36,11 @@ class ThreeDCamera(CameraWithPerspective): def __init__(self, *args, **kwargs): Camera.__init__(self, *args, **kwargs) self.unit_sun_vect = self.sun_vect/np.linalg.norm(self.sun_vect) - ## Lives in the phi-theta-distance space + ## rotation_mobject lives in the phi-theta-distance space 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.set_position(self.phi, self.theta, self.distance) def get_color(self, method): @@ -126,6 +129,16 @@ class ThreeDCamera(CameraWithPerspective): np.cos(phi) ]) + def get_center_of_rotation(self, x = None, y = None, z = None): + curr_x, curr_y, curr_z = self.moving_center.points[0] + if x is None: + x = curr_x + if y is None: + y = curr_y + if z is None: + z = curr_z + return np.array([x, y, z]) + def set_position(self, phi = None, theta = None, distance = None): point = self.get_spherical_coords(phi, theta, distance) self.rotation_mobject.move_to(point) @@ -140,6 +153,8 @@ 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] + return Camera.points_to_pixel_coords(self, new_points) class ThreeDScene(Scene): @@ -167,6 +182,7 @@ class ThreeDScene(Scene): def move_camera( self, phi = None, theta = None, distance = None, + center_x = None, center_y = None, center_z = None, added_anims = [], **kwargs ): @@ -176,10 +192,17 @@ class ThreeDScene(Scene): target_point, **kwargs ) + target_center = self.camera.get_center_of_rotation(center_x, center_y, center_z) + movement_center = ApplyMethod( + self.camera.moving_center.move_to, + target_center, + **kwargs + ) is_camera_rotating = self.ambient_camera_rotation in self.continual_animations if is_camera_rotating: self.remove(self.ambient_camera_rotation) - self.play(movement, *added_anims) + self.play(movement, movement_center, *added_anims) + target_point = self.camera.get_spherical_coords(phi, theta, distance) if is_camera_rotating: self.add(self.ambient_camera_rotation) From fb458de37d4531a6998af8d03134ba558768af49 Mon Sep 17 00:00:00 2001 From: frozar Date: Fri, 2 Feb 2018 11:10:17 +0100 Subject: [PATCH 2/3] [3D CAMERA] Add an example 'Rotation3d' to see the feature. --- example_scenes.py | 63 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/example_scenes.py b/example_scenes.py index 6855b3cd..4561c1fc 100644 --- a/example_scenes.py +++ b/example_scenes.py @@ -23,6 +23,8 @@ from mobject.tex_mobject import * from mobject.vectorized_mobject import * +from topics.three_dimensions import * + # To watch one of these scenes, run the following: # python extract_scene.py file_name -p # @@ -58,6 +60,67 @@ class WriteStuff(Scene): self.play(Write(TextMobject("Stuff").scale(3))) +class Rotation3d(ThreeDScene): + def construct(self): + # STEP 1 + # Build two cube in the 3D scene, one for around the origin, + # the other shifted along the vector RIGHT + UP + OUT + cube_origin = Cube(fill_opacity = 0.8, stroke_width = 1., + side_length = 1., fill_color = WHITE) + + # RIGHT side: Red + # UP side: Green + # OUT side: Blue + orientations = [IN, OUT, LEFT, RIGHT, UP, DOWN] + for face, orient in zip(cube_origin.family_members_with_points(), orientations): + if np.array_equal(orient, RIGHT): + face.set_style_data(fill_color = RED) + elif np.array_equal(orient, UP): + face.set_style_data(fill_color = GREEN) + elif np.array_equal(orient, OUT): + face.set_style_data(fill_color = BLUE) + + cube_shifted = Cube(fill_opacity = 0.8, stroke_width = 1., + side_length = 1., fill_color = BLUE) + shift_vec = 2*(RIGHT + UP + OUT) + cube_shifted.shift(shift_vec) + + # STEP 2 + # Add the cubes in the 3D scene + self.add(cube_origin) + self.add(cube_shifted) + + # STEP 3 + # Setup the camera position + phi, theta, distance = ThreeDCamera().get_spherical_coords() + angle_factor = 0.9 + phi += 2*np.pi/4*angle_factor + theta += 3*2*np.pi/8 + self.set_camera_position(phi, theta, distance) + self.wait() + + # STEP 4 + # Animation + # Animation 1: rotation around the Z-axis with the ORIGIN of the space + # as center of rotation + theta += 2*np.pi + self.move_camera(phi, theta, distance, + run_time = 5) + + # Animation 2: shift the space in order of to get the center of the shifted cube + # as the next center of rotation + cube_center = cube_shifted.get_center() + self.move_camera(center_x = cube_center[0], + center_y = cube_center[1], + center_z = cube_center[2], + run_time = 2) + + # Animation 3: rotation around the Z-axis with the center of the shifted cube + # as center of rotation + theta += 2*np.pi + self.move_camera(phi, theta, distance, + run_time = 5) + From 2c85f66dddd470656d773c9c45800e10296b2b48 Mon Sep 17 00:00:00 2001 From: frozar Date: Fri, 2 Feb 2018 15:12:07 +0100 Subject: [PATCH 3/3] [3D CAMERA] Add parameter to set the camera position. --- topics/three_dimensions.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/topics/three_dimensions.py b/topics/three_dimensions.py index 809979f5..ba9611cb 100644 --- a/topics/three_dimensions.py +++ b/topics/three_dimensions.py @@ -139,10 +139,14 @@ class ThreeDCamera(CameraWithPerspective): z = curr_z return np.array([x, y, z]) - def set_position(self, phi = None, theta = None, distance = None): + def set_position(self, phi = None, theta = None, distance = None, + center_x = None, center_y = None, center_z = None): point = self.get_spherical_coords(phi, theta, distance) self.rotation_mobject.move_to(point) self.phi, self.theta, self.distance = point + 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] def get_view_transformation_matrix(self): return (self.default_distance / self.get_distance()) * np.dot( @@ -163,8 +167,9 @@ class ThreeDScene(Scene): "ambient_camera_rotation" : None, } - def set_camera_position(self, phi = None, theta = None, distance = None): - self.camera.set_position(phi, theta, distance) + def set_camera_position(self, phi = None, theta = None, distance = None, + center_x = None, center_y = None, center_z = None): + self.camera.set_position(phi, theta, distance, center_x, center_y, center_z) def begin_ambient_camera_rotation(self, rate = 0.01): self.ambient_camera_rotation = AmbientMovement( @@ -180,9 +185,9 @@ class ThreeDScene(Scene): self.ambient_camera_rotation = None def move_camera( - self, + self, phi = None, theta = None, distance = None, - center_x = None, center_y = None, center_z = None, + center_x = None, center_y = None, center_z = None, added_anims = [], **kwargs ):