mirror of
https://github.com/3b1b/manim.git
synced 2025-08-05 16:49:03 +00:00
Improve readability of three_dimensions
This commit is contained in:
parent
e003bf5c47
commit
cc63caeec0
1 changed files with 173 additions and 71 deletions
|
@ -1,4 +1,6 @@
|
||||||
|
|
||||||
from helpers import *
|
from helpers import *
|
||||||
|
|
||||||
from mobject.vectorized_mobject import VGroup, VMobject, VectorizedPoint
|
from mobject.vectorized_mobject import VGroup, VMobject, VectorizedPoint
|
||||||
from topics.geometry import Square, Line
|
from topics.geometry import Square, Line
|
||||||
from scene import Scene
|
from scene import Scene
|
||||||
|
@ -6,32 +8,38 @@ from camera import Camera
|
||||||
from animation.continual_animation import AmbientMovement
|
from animation.continual_animation import AmbientMovement
|
||||||
from animation.transform import ApplyMethod
|
from animation.transform import ApplyMethod
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
class CameraWithPerspective(Camera):
|
class CameraWithPerspective(Camera):
|
||||||
CONFIG = {'camera_distance': 20}
|
CONFIG = {
|
||||||
|
"camera_distance" : 20,
|
||||||
|
}
|
||||||
def points_to_pixel_coords(self, points):
|
def points_to_pixel_coords(self, points):
|
||||||
distance_ratios = np.divide(self.camera_distance, self.camera_distance - points[:, 2])
|
distance_ratios = np.divide(
|
||||||
|
self.camera_distance,
|
||||||
|
self.camera_distance - points[:,2]
|
||||||
|
)
|
||||||
scale_factors = interpolate(0, 1, distance_ratios)
|
scale_factors = interpolate(0, 1, distance_ratios)
|
||||||
adjusted_points = np.array(points)
|
adjusted_points = np.array(points)
|
||||||
for i in (0, 1):
|
for i in 0, 1:
|
||||||
adjusted_points[(:, i)] *= scale_factors
|
adjusted_points[:,i] *= scale_factors
|
||||||
|
|
||||||
return Camera.points_to_pixel_coords(self, adjusted_points)
|
return Camera.points_to_pixel_coords(self, adjusted_points)
|
||||||
|
|
||||||
|
|
||||||
class ThreeDCamera(CameraWithPerspective):
|
class ThreeDCamera(CameraWithPerspective):
|
||||||
CONFIG = {'sun_vect': 5 * UP + LEFT,
|
CONFIG = {
|
||||||
'shading_factor': 0.2,
|
"sun_vect" : 5*UP+LEFT,
|
||||||
'distance': 5.0,
|
"shading_factor" : 0.2,
|
||||||
'default_distance': 5.0,
|
"distance" : 5.,
|
||||||
'phi': 0,
|
"default_distance" : 5.,
|
||||||
'theta': -TAU / 4}
|
"phi" : 0, #Angle off z axis
|
||||||
|
"theta" : -TAU/4, #Rotation about z axis
|
||||||
|
}
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
Camera.__init__(self, *args, **kwargs)
|
Camera.__init__(self, *args, **kwargs)
|
||||||
self.unit_sun_vect = self.sun_vect / np.linalg.norm(self.sun_vect)
|
self.unit_sun_vect = self.sun_vect/np.linalg.norm(self.sun_vect)
|
||||||
|
## rotation_mobject lives in the phi-theta-distance space
|
||||||
self.rotation_mobject = VectorizedPoint()
|
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.space_center)
|
||||||
self.set_position(self.phi, self.theta, self.distance)
|
self.set_position(self.phi, self.theta, self.distance)
|
||||||
|
|
||||||
|
@ -48,56 +56,64 @@ class ThreeDCamera(CameraWithPerspective):
|
||||||
return self.modified_rgb(vmobject, vmobject.get_fill_rgb())
|
return self.modified_rgb(vmobject, vmobject.get_fill_rgb())
|
||||||
|
|
||||||
def get_shaded_rgb(self, rgb, normal_vect):
|
def get_shaded_rgb(self, rgb, normal_vect):
|
||||||
brightness = np.dot(normal_vect, self.unit_sun_vect) ** 2
|
brightness = np.dot(normal_vect, self.unit_sun_vect)**2
|
||||||
if brightness > 0:
|
if brightness > 0:
|
||||||
alpha = self.shading_factor * brightness
|
alpha = self.shading_factor*brightness
|
||||||
return interpolate(rgb, np.ones(3), alpha)
|
return interpolate(rgb, np.ones(3), alpha)
|
||||||
else:
|
else:
|
||||||
alpha = -self.shading_factor * brightness
|
alpha = -self.shading_factor*brightness
|
||||||
return interpolate(rgb, np.zeros(3), alpha)
|
return interpolate(rgb, np.zeros(3), alpha)
|
||||||
|
|
||||||
def get_unit_normal_vect(self, vmobject):
|
def get_unit_normal_vect(self, vmobject):
|
||||||
anchors = vmobject.get_anchors()
|
anchors = vmobject.get_anchors()
|
||||||
if len(anchors) < 3:
|
if len(anchors) < 3:
|
||||||
return OUT
|
return OUT
|
||||||
normal = np.cross(anchors[1] - anchors[0], anchors[2] - anchors[1])
|
normal = np.cross(anchors[1]-anchors[0], anchors[2]-anchors[1])
|
||||||
if normal[2] < 0:
|
if normal[2] < 0:
|
||||||
normal = -normal
|
normal = -normal
|
||||||
length = np.linalg.norm(normal)
|
length = np.linalg.norm(normal)
|
||||||
if length == 0:
|
if length == 0:
|
||||||
return OUT
|
return OUT
|
||||||
return normal / length
|
return normal/length
|
||||||
|
|
||||||
def display_multiple_vectorized_mobjects(self, vmobjects):
|
def display_multiple_vectorized_mobjects(self, vmobjects):
|
||||||
camera_point = self.spherical_coords_to_point(*self.get_spherical_coords())
|
camera_point = self.spherical_coords_to_point(
|
||||||
|
*self.get_spherical_coords()
|
||||||
|
)
|
||||||
def z_cmp(*vmobs):
|
def z_cmp(*vmobs):
|
||||||
|
# Compare to three dimensional mobjects based on
|
||||||
|
# how close they are to the camera
|
||||||
|
# return cmp(*[
|
||||||
|
# -np.linalg.norm(vm.get_center()-camera_point)
|
||||||
|
# for vm in vmobs
|
||||||
|
# ])
|
||||||
three_d_status = map(should_shade_in_3d, vmobs)
|
three_d_status = map(should_shade_in_3d, vmobs)
|
||||||
has_points = [ vm.get_num_points() > 0 for vm in vmobs ]
|
has_points = [vm.get_num_points() > 0 for vm in vmobs]
|
||||||
if all(three_d_status) and all(has_points):
|
if all(three_d_status) and all(has_points):
|
||||||
cmp_vect = self.get_unit_normal_vect(vmobs[1])
|
cmp_vect = self.get_unit_normal_vect(vmobs[1])
|
||||||
return cmp(*[ np.dot(vm.get_center(), cmp_vect) for vm in vmobs ])
|
return cmp(*[
|
||||||
|
np.dot(vm.get_center(), cmp_vect)
|
||||||
|
for vm in vmobs
|
||||||
|
])
|
||||||
else:
|
else:
|
||||||
return 0
|
return 0
|
||||||
|
Camera.display_multiple_vectorized_mobjects(
|
||||||
Camera.display_multiple_vectorized_mobjects(self, sorted(vmobjects, cmp=z_cmp))
|
self, sorted(vmobjects, cmp = z_cmp)
|
||||||
|
)
|
||||||
|
|
||||||
def get_spherical_coords(self, phi = None, theta = None, distance = None):
|
def get_spherical_coords(self, phi = None, theta = None, distance = None):
|
||||||
curr_phi, curr_theta, curr_d = self.rotation_mobject.points[0]
|
curr_phi, curr_theta, curr_d = self.rotation_mobject.points[0]
|
||||||
if phi is None:
|
if phi is None: phi = curr_phi
|
||||||
phi = curr_phi
|
if theta is None: theta = curr_theta
|
||||||
if theta is None:
|
if distance is None: distance = curr_d
|
||||||
theta = curr_theta
|
|
||||||
if distance is None:
|
|
||||||
distance = curr_d
|
|
||||||
return np.array([phi, theta, distance])
|
return np.array([phi, theta, distance])
|
||||||
|
|
||||||
def get_cartesian_coords(self, phi = None, theta = None, distance = None):
|
def get_cartesian_coords(self, phi = None, theta = None, distance = None):
|
||||||
spherical_coords_array = self.get_spherical_coords(phi, theta, distance)
|
spherical_coords_array = self.get_spherical_coords(phi,theta,distance)
|
||||||
phi2 = spherical_coords_array[0]
|
phi2 = spherical_coords_array[0]
|
||||||
theta2 = spherical_coords_array[1]
|
theta2 = spherical_coords_array[1]
|
||||||
d2 = spherical_coords_array[2]
|
d2 = spherical_coords_array[2]
|
||||||
return self.spherical_coords_to_point(phi2, theta2, d2)
|
return self.spherical_coords_to_point(phi2,theta2,d2)
|
||||||
|
|
||||||
def get_phi(self):
|
def get_phi(self):
|
||||||
return self.get_spherical_coords()[0]
|
return self.get_spherical_coords()[0]
|
||||||
|
@ -109,7 +125,11 @@ class ThreeDCamera(CameraWithPerspective):
|
||||||
return self.get_spherical_coords()[2]
|
return self.get_spherical_coords()[2]
|
||||||
|
|
||||||
def spherical_coords_to_point(self, phi, theta, distance):
|
def spherical_coords_to_point(self, phi, theta, distance):
|
||||||
return distance * np.array([np.sin(phi) * np.cos(theta), np.sin(phi) * np.sin(theta), np.cos(phi)])
|
return distance*np.array([
|
||||||
|
np.sin(phi)*np.cos(theta),
|
||||||
|
np.sin(phi)*np.sin(theta),
|
||||||
|
np.cos(phi)
|
||||||
|
])
|
||||||
|
|
||||||
def get_center_of_rotation(self, x = None, y = None, z = None):
|
def get_center_of_rotation(self, x = None, y = None, z = None):
|
||||||
curr_x, curr_y, curr_z = self.moving_center.points[0]
|
curr_x, curr_y, curr_z = self.moving_center.points[0]
|
||||||
|
@ -121,7 +141,8 @@ class ThreeDCamera(CameraWithPerspective):
|
||||||
z = curr_z
|
z = curr_z
|
||||||
return np.array([x, y, z])
|
return np.array([x, y, z])
|
||||||
|
|
||||||
def set_position(self, phi = None, theta = None, distance = None, center_x = None, center_y = None, center_z = 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)
|
point = self.get_spherical_coords(phi, theta, distance)
|
||||||
self.rotation_mobject.move_to(point)
|
self.rotation_mobject.move_to(point)
|
||||||
self.phi, self.theta, self.distance = point
|
self.phi, self.theta, self.distance = point
|
||||||
|
@ -130,24 +151,34 @@ class ThreeDCamera(CameraWithPerspective):
|
||||||
self.space_center = self.moving_center.points[0]
|
self.space_center = self.moving_center.points[0]
|
||||||
|
|
||||||
def get_view_transformation_matrix(self):
|
def get_view_transformation_matrix(self):
|
||||||
return self.default_distance / self.get_distance() * np.dot(rotation_matrix(self.get_phi(), LEFT), rotation_about_z(-self.get_theta() - np.pi / 2))
|
return (self.default_distance / self.get_distance()) * np.dot(
|
||||||
|
rotation_matrix(self.get_phi(), LEFT),
|
||||||
|
rotation_about_z(-self.get_theta() - np.pi/2),
|
||||||
|
)
|
||||||
|
|
||||||
def points_to_pixel_coords(self, points):
|
def points_to_pixel_coords(self, points):
|
||||||
matrix = self.get_view_transformation_matrix()
|
matrix = self.get_view_transformation_matrix()
|
||||||
new_points = np.dot(points, matrix.T)
|
new_points = np.dot(points, matrix.T)
|
||||||
self.space_center = self.moving_center.points[0]
|
self.space_center = self.moving_center.points[0]
|
||||||
|
|
||||||
return Camera.points_to_pixel_coords(self, new_points)
|
return Camera.points_to_pixel_coords(self, new_points)
|
||||||
|
|
||||||
|
|
||||||
class ThreeDScene(Scene):
|
class ThreeDScene(Scene):
|
||||||
CONFIG = {'camera_class': ThreeDCamera,
|
CONFIG = {
|
||||||
'ambient_camera_rotation': None}
|
"camera_class" : ThreeDCamera,
|
||||||
|
"ambient_camera_rotation" : None,
|
||||||
|
}
|
||||||
|
|
||||||
def set_camera_position(self, phi = None, theta = None, distance = None, center_x = None, center_y = None, center_z = None):
|
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)
|
self.camera.set_position(phi, theta, distance, center_x, center_y, center_z)
|
||||||
|
|
||||||
def begin_ambient_camera_rotation(self, rate = 0.01):
|
def begin_ambient_camera_rotation(self, rate = 0.01):
|
||||||
self.ambient_camera_rotation = AmbientMovement(self.camera.rotation_mobject, direction=UP, rate=rate)
|
self.ambient_camera_rotation = AmbientMovement(
|
||||||
|
self.camera.rotation_mobject,
|
||||||
|
direction = UP,
|
||||||
|
rate = rate
|
||||||
|
)
|
||||||
self.add(self.ambient_camera_rotation)
|
self.add(self.ambient_camera_rotation)
|
||||||
|
|
||||||
def stop_ambient_camera_rotation(self):
|
def stop_ambient_camera_rotation(self):
|
||||||
|
@ -155,11 +186,25 @@ class ThreeDScene(Scene):
|
||||||
self.remove(self.ambient_camera_rotation)
|
self.remove(self.ambient_camera_rotation)
|
||||||
self.ambient_camera_rotation = None
|
self.ambient_camera_rotation = None
|
||||||
|
|
||||||
def move_camera(self, phi = None, theta = None, distance = None, center_x = None, center_y = None, center_z = None, added_anims = [], **kwargs):
|
def move_camera(
|
||||||
|
self,
|
||||||
|
phi = None, theta = None, distance = None,
|
||||||
|
center_x = None, center_y = None, center_z = None,
|
||||||
|
added_anims = [],
|
||||||
|
**kwargs
|
||||||
|
):
|
||||||
target_point = self.camera.get_spherical_coords(phi, theta, distance)
|
target_point = self.camera.get_spherical_coords(phi, theta, distance)
|
||||||
movement = ApplyMethod(self.camera.rotation_mobject.move_to, target_point, **kwargs)
|
movement = ApplyMethod(
|
||||||
|
self.camera.rotation_mobject.move_to,
|
||||||
|
target_point,
|
||||||
|
**kwargs
|
||||||
|
)
|
||||||
target_center = self.camera.get_center_of_rotation(center_x, center_y, center_z)
|
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)
|
movement_center = ApplyMethod(
|
||||||
|
self.camera.moving_center.move_to,
|
||||||
|
target_center,
|
||||||
|
**kwargs
|
||||||
|
)
|
||||||
is_camera_rotating = self.ambient_camera_rotation in self.continual_animations
|
is_camera_rotating = self.ambient_camera_rotation in self.continual_animations
|
||||||
if is_camera_rotating:
|
if is_camera_rotating:
|
||||||
self.remove(self.ambient_camera_rotation)
|
self.remove(self.ambient_camera_rotation)
|
||||||
|
@ -174,34 +219,33 @@ class ThreeDScene(Scene):
|
||||||
return list_update(self.mobjects, moving_mobjects)
|
return list_update(self.mobjects, moving_mobjects)
|
||||||
return moving_mobjects
|
return moving_mobjects
|
||||||
|
|
||||||
|
##############
|
||||||
|
|
||||||
def should_shade_in_3d(mobject):
|
def should_shade_in_3d(mobject):
|
||||||
return hasattr(mobject, 'shade_in_3d') and mobject.shade_in_3d
|
return hasattr(mobject, "shade_in_3d") and mobject.shade_in_3d
|
||||||
|
|
||||||
|
|
||||||
def shade_in_3d(mobject):
|
def shade_in_3d(mobject):
|
||||||
for submob in mobject.submobject_family():
|
for submob in mobject.submobject_family():
|
||||||
submob.shade_in_3d = True
|
submob.shade_in_3d = True
|
||||||
|
|
||||||
|
|
||||||
def turn_off_3d_shading(mobject):
|
def turn_off_3d_shading(mobject):
|
||||||
for submob in mobject.submobject_family():
|
for submob in mobject.submobject_family():
|
||||||
submob.shade_in_3d = False
|
submob.shade_in_3d = False
|
||||||
|
|
||||||
|
|
||||||
class ThreeDMobject(VMobject):
|
class ThreeDMobject(VMobject):
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
VMobject.__init__(self, *args, **kwargs)
|
VMobject.__init__(self, *args, **kwargs)
|
||||||
shade_in_3d(self)
|
shade_in_3d(self)
|
||||||
|
|
||||||
|
|
||||||
class Cube(ThreeDMobject):
|
class Cube(ThreeDMobject):
|
||||||
CONFIG = {'fill_opacity': 0.75,
|
CONFIG = {
|
||||||
'fill_color': BLUE,
|
'fill_opacity': 0.75,
|
||||||
'stroke_width': 0,
|
'fill_color': BLUE,
|
||||||
'propagate_style_to_family': True,
|
'stroke_width': 0,
|
||||||
'side_length': 2}
|
'propagate_style_to_family': True,
|
||||||
|
'side_length': 2
|
||||||
|
}
|
||||||
|
|
||||||
def generate_points(self):
|
def generate_points(self):
|
||||||
for vect in (IN,
|
for vect in (IN,
|
||||||
|
@ -216,34 +260,82 @@ class Cube(ThreeDMobject):
|
||||||
self.add(face)
|
self.add(face)
|
||||||
|
|
||||||
|
|
||||||
class SphereThreeD(ThreeDMobject):
|
class Sphere(ThreeDMobject):
|
||||||
|
CONFIG = {
|
||||||
def __init__(self, r, eps):
|
'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.r = r
|
||||||
self.eps = eps
|
self.eps = eps
|
||||||
|
self.CONFIG['fill_opacity'] = opacity
|
||||||
ThreeDMobject.__init__(self)
|
ThreeDMobject.__init__(self)
|
||||||
|
|
||||||
CONFIG = {'fill_opacity': 0.75,
|
|
||||||
'fill_color': BLUE,
|
|
||||||
'stroke_width': 0,
|
|
||||||
'propagate_style_to_family': True,
|
|
||||||
'side_length': 2}
|
|
||||||
|
|
||||||
def generate_points(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) ]
|
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:
|
for vect in points:
|
||||||
face = Square(side_length=self.eps)
|
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))
|
face.apply_function(lambda p: np.dot(p, z_to_vector(vect).T))
|
||||||
self.add(face)
|
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):
|
class Parametric3D(ThreeDMobject):
|
||||||
CONFIG = {'fill_opacity': 0.75,
|
CONFIG = {
|
||||||
'fill_color': BLUE,
|
'fill_opacity': 0.75,
|
||||||
'stroke_width': 0,
|
'fill_color': BLUE,
|
||||||
'propagate_style_to_family': True}
|
'stroke_width': 0,
|
||||||
|
'propagate_style_to_family': True
|
||||||
|
}
|
||||||
|
|
||||||
def __init__(self, f, g, h, phi_min, phi_max, theta_min, theta_max, eps):
|
def __init__(self, f, g, h, phi_min, phi_max, theta_min, theta_max, eps, opacity = .75):
|
||||||
self.f = f
|
self.f = f
|
||||||
self.g = g
|
self.g = g
|
||||||
self.h = h
|
self.h = h
|
||||||
|
@ -252,16 +344,26 @@ class Parametric3D(ThreeDMobject):
|
||||||
self.theta_min = theta_min
|
self.theta_min = theta_min
|
||||||
self.theta_max = theta_max
|
self.theta_max = theta_max
|
||||||
self.eps = eps
|
self.eps = eps
|
||||||
|
self.CONFIG['fill_opacity'] = opacity
|
||||||
ThreeDMobject.__init__(self)
|
ThreeDMobject.__init__(self)
|
||||||
|
|
||||||
def generate_points(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) ]
|
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:
|
for vect in points:
|
||||||
face = Square(side_length=self.eps)
|
face = Square(side_length=self.eps)
|
||||||
scalefactor = np.linalg.norm(vect)
|
scalefactor = np.linalg.norm(vect)
|
||||||
face.shift(scalefactor * OUT / 2.0)
|
face.shift(scalefactor * OUT / 2.0)
|
||||||
face.apply_function(lambda p: np.dot(p, z_to_vector(vect).T))
|
face.apply_function(lambda p: np.dot(p, z_to_vector(vect).T))
|
||||||
self.add(face)
|
self.add(face)
|
||||||
|
shade_in_3d(self)
|
||||||
|
|
||||||
|
|
||||||
class Prism(Cube):
|
class Prism(Cube):
|
||||||
|
|
Loading…
Add table
Reference in a new issue