diff --git a/topics/three_dimensions.py b/topics/three_dimensions.py index 752e4818..5fc3fe68 100644 --- a/topics/three_dimensions.py +++ b/topics/three_dimensions.py @@ -7,7 +7,7 @@ from scene import Scene from camera import Camera from animation.continual_animation import AmbientMovement from animation.transform import ApplyMethod - +import numpy as np class CameraWithPerspective(Camera): CONFIG = { "camera_distance" : 20, @@ -237,53 +237,139 @@ class ThreeDMobject(VMobject): VMobject.__init__(self, *args, **kwargs) shade_in_3d(self) + class Cube(ThreeDMobject): CONFIG = { - "fill_opacity" : 0.75, - "fill_color" : BLUE, - "stroke_width" : 0, - "propagate_style_to_family" : True, - "side_length" : 2, + 'fill_opacity': 0.75, + 'fill_color': BLUE, + 'stroke_width': 0, + 'propagate_style_to_family': True, + 'side_length': 2 } - def generate_points(self): - for vect in IN, OUT, LEFT, RIGHT, UP, DOWN: - face = Square(side_length = self.side_length) - face.shift(self.side_length*OUT/2.0) - face.apply_function(lambda p : np.dot(p, z_to_vector(vect).T)) + def generate_points(self): + for vect in (IN, + OUT, + LEFT, + RIGHT, + UP, + DOWN): + face = Square(side_length=self.side_length) + face.shift(self.side_length * OUT / 2.0) + face.apply_function(lambda p: np.dot(p, z_to_vector(vect).T)) self.add(face) -class Prism(Cube): + +class Sphere(ThreeDMobject): CONFIG = { - "dimensions" : [3, 2, 1] + 'fill_opacity': .75, + 'fill_color': BLUE, + 'stroke_width': 0, + 'propagate_style_to_family': True, + 'side_length': 2 } + def __init__(self, r, eps, opacity = .75): + self.r = r + self.eps = eps + self.CONFIG['fill_opacity'] = opacity + ThreeDMobject.__init__(self) + + def generate_points(self): + points = [ + ( + self.r * (np.sin(phi) * np.cos(theta)), + self.r * (np.sin(phi) * np.sin(theta)), + self.r * np.cos(phi) + ) + for phi in np.arange(0, 2 * np.pi, self.eps) + for theta in np.arange(0, 2 * np.pi, self.eps) + ] + for vect in points: + face = Square(side_length=self.eps) + scalefactor = np.linalg.norm(vect) + face.shift(scalefactor * OUT / 2.0) + face.apply_function(lambda p: np.dot(p, z_to_vector(vect).T)) + self.add(face) + shade_in_3d(self) + +class Torus(ThreeDMobject): + CONFIG = { + 'fill_opacity': .75, + 'fill_color': BLUE, + 'stroke_width': 0, + 'propagate_style_to_family': True, + 'side_length': 2 + } + def __init__(self, r1, r2, eps, opacity=.75): + self.r1 = r1 + self.r2 = r2 + self.eps = eps + self.CONFIG['fill_opacity'] = opacity + ThreeDMobject.__init__(self) + + + def generate_points(self): + points = [ + ( + (self.r1 + self.r2 * np.cos(theta)) * np.cos(phi), + (self.r1 + self.r2 * np.cos(theta)) * np.sin(phi), + self.r2 * np.sin(theta) + ) + for phi in np.arange(0, 2 * np.pi, self.eps) + for theta in np.arange(0, 2 * np.pi, self.eps) + ] + for vect in points: + face = Square(side_length=self.eps) + scalefactor = np.linalg.norm(vect) + face.shift(scalefactor * OUT / 2.0) + face.apply_function(lambda p: np.dot(p, z_to_vector(vect).T)) + self.add(face) + shade_in_3d(self) + + +class Parametric3D(ThreeDMobject): + CONFIG = { + 'fill_opacity': 0.75, + 'fill_color': BLUE, + 'stroke_width': 0, + 'propagate_style_to_family': True + } + + def __init__(self, f, g, h, phi_min, phi_max, theta_min, theta_max, eps, opacity = .75): + self.f = f + self.g = g + self.h = h + self.phi_min = phi_min + self.phi_max = phi_max + self.theta_min = theta_min + self.theta_max = theta_max + self.eps = eps + self.CONFIG['fill_opacity'] = opacity + ThreeDMobject.__init__(self) + + def generate_points(self): + points = [ + ( + self.f(phi, theta), + self.g(phi, theta), + self.h(phi, theta) + ) + for phi in np.arange(self.phi_min, self.phi_max, self.eps) + for theta in np.arange(self.theta_min, self.theta_max, self.eps) + ] + for vect in points: + face = Square(side_length=self.eps) + scalefactor = np.linalg.norm(vect) + face.shift(scalefactor * OUT / 2.0) + face.apply_function(lambda p: np.dot(p, z_to_vector(vect).T)) + self.add(face) + shade_in_3d(self) + + +class Prism(Cube): + CONFIG = {'dimensions': [3, 2, 1]} + def generate_points(self): Cube.generate_points(self) for dim, value in enumerate(self.dimensions): - self.rescale_to_fit(value, dim, stretch = True) - - - - - - - - - - - - - - - - - - - - - - - - - - + self.rescale_to_fit(value, dim, stretch=True) \ No newline at end of file