mirror of
https://github.com/3b1b/manim.git
synced 2025-07-29 21:12:35 +08:00
A few 3d updates
This commit is contained in:
@ -64,14 +64,17 @@ class Animation(object):
|
|||||||
#Typically ipmlemented by subclass
|
#Typically ipmlemented by subclass
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def get_all_families_zipped(self):
|
def get_all_mobjects(self):
|
||||||
"""
|
"""
|
||||||
Ordering must match the ording of arguments to update_submobject
|
Ordering must match the ording of arguments to update_submobject
|
||||||
"""
|
"""
|
||||||
return zip(
|
return self.mobject, self.starting_mobject
|
||||||
self.mobject.submobject_family(),
|
|
||||||
self.starting_mobject.submobject_family()
|
def get_all_families_zipped(self):
|
||||||
)
|
return zip(*map(
|
||||||
|
Mobject.family_members_with_points,
|
||||||
|
self.get_all_mobjects()
|
||||||
|
))
|
||||||
|
|
||||||
def get_sub_alpha(self, alpha, index, num_submobjects):
|
def get_sub_alpha(self, alpha, index, num_submobjects):
|
||||||
if self.submobject_mode in ["lagged_start", "smoothed_lagged_start"]:
|
if self.submobject_mode in ["lagged_start", "smoothed_lagged_start"]:
|
||||||
|
@ -13,6 +13,7 @@ from mobject import Mobject, Point, VMobject, Group
|
|||||||
class Transform(Animation):
|
class Transform(Animation):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"path_arc" : 0,
|
"path_arc" : 0,
|
||||||
|
"path_arc_axis" : OUT,
|
||||||
"path_func" : None,
|
"path_func" : None,
|
||||||
"submobject_mode" : "all_at_once",
|
"submobject_mode" : "all_at_once",
|
||||||
"replace_mobject_with_target_in_scene" : False,
|
"replace_mobject_with_target_in_scene" : False,
|
||||||
@ -31,7 +32,10 @@ class Transform(Animation):
|
|||||||
def update_config(self, **kwargs):
|
def update_config(self, **kwargs):
|
||||||
Animation.update_config(self, **kwargs)
|
Animation.update_config(self, **kwargs)
|
||||||
if "path_arc" in kwargs:
|
if "path_arc" in kwargs:
|
||||||
self.path_func = path_along_arc(kwargs["path_arc"])
|
self.path_func = path_along_arc(
|
||||||
|
kwargs["path_arc"],
|
||||||
|
kwargs["path_arc_axis"]
|
||||||
|
)
|
||||||
|
|
||||||
def init_path_func(self):
|
def init_path_func(self):
|
||||||
if self.path_func is not None:
|
if self.path_func is not None:
|
||||||
@ -39,13 +43,13 @@ class Transform(Animation):
|
|||||||
if self.path_arc == 0:
|
if self.path_arc == 0:
|
||||||
self.path_func = straight_path
|
self.path_func = straight_path
|
||||||
else:
|
else:
|
||||||
self.path_func = path_along_arc(self.path_arc)
|
self.path_func = path_along_arc(
|
||||||
|
self.path_arc,
|
||||||
|
self.path_arc_axis,
|
||||||
|
)
|
||||||
|
|
||||||
def get_all_families_zipped(self):
|
def get_all_mobjects(self):
|
||||||
return zip(*map(
|
return self.mobject, self.starting_mobject, self.target_mobject
|
||||||
Mobject.submobject_family,
|
|
||||||
[self.mobject, self.starting_mobject, self.target_mobject]
|
|
||||||
))
|
|
||||||
|
|
||||||
def update_submobject(self, submob, start, end, alpha):
|
def update_submobject(self, submob, start, end, alpha):
|
||||||
submob.interpolate(start, end, alpha, self.path_func)
|
submob.interpolate(start, end, alpha, self.path_func)
|
||||||
@ -169,6 +173,8 @@ class Rotate(ApplyMethod):
|
|||||||
def __init__(self, mobject, angle = np.pi, axis = OUT, **kwargs):
|
def __init__(self, mobject, angle = np.pi, axis = OUT, **kwargs):
|
||||||
if "path_arc" not in kwargs:
|
if "path_arc" not in kwargs:
|
||||||
kwargs["path_arc"] = angle
|
kwargs["path_arc"] = angle
|
||||||
|
if "path_arc_axis" not in kwargs:
|
||||||
|
kwargs["path_arc_axis"] = axis
|
||||||
digest_config(self, kwargs, locals())
|
digest_config(self, kwargs, locals())
|
||||||
target = mobject.copy()
|
target = mobject.copy()
|
||||||
if self.in_place:
|
if self.in_place:
|
||||||
|
41
camera.py
41
camera.py
@ -288,47 +288,6 @@ class MovingCamera(Camera):
|
|||||||
0 if self.aligned_dimension == "height" else 1
|
0 if self.aligned_dimension == "height" else 1
|
||||||
)
|
)
|
||||||
|
|
||||||
class ShadingCamera(Camera):
|
|
||||||
CONFIG = {
|
|
||||||
# "sun_vect" : OUT+LEFT+UP,
|
|
||||||
"sun_vect" : UP+LEFT,
|
|
||||||
"shading_factor" : 0.5,
|
|
||||||
}
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
Camera.__init__(self, *args, **kwargs)
|
|
||||||
self.unit_sun_vect = self.sun_vect/np.linalg.norm(self.sun_vect)
|
|
||||||
|
|
||||||
def get_stroke_color(self, vmobject):
|
|
||||||
return Color(rgb = self.get_shaded_rgb(
|
|
||||||
color_to_rgb(vmobject.get_stroke_color()),
|
|
||||||
normal_vect = self.get_unit_normal_vect(vmobject)
|
|
||||||
))
|
|
||||||
|
|
||||||
def get_fill_color(self, vmobject):
|
|
||||||
return Color(rgb = self.get_shaded_rgb(
|
|
||||||
color_to_rgb(vmobject.get_fill_color()),
|
|
||||||
normal_vect = self.get_unit_normal_vect(vmobject)
|
|
||||||
))
|
|
||||||
|
|
||||||
def get_shaded_rgb(self, rgb, normal_vect):
|
|
||||||
brightness = np.dot(normal_vect, self.unit_sun_vect)
|
|
||||||
if brightness > 0:
|
|
||||||
alpha = self.shading_factor*brightness
|
|
||||||
return interpolate(rgb, np.ones(3), alpha)
|
|
||||||
else:
|
|
||||||
alpha = -self.shading_factor*brightness
|
|
||||||
return interpolate(rgb, np.zeros(3), alpha)
|
|
||||||
|
|
||||||
def get_unit_normal_vect(self, vmobject):
|
|
||||||
anchors = vmobject.get_anchors()
|
|
||||||
if len(anchors) < 3:
|
|
||||||
return OUT
|
|
||||||
normal = np.cross(anchors[1]-anchors[0], anchors[2]-anchors[1])
|
|
||||||
length = np.linalg.norm(normal)
|
|
||||||
if length == 0:
|
|
||||||
return OUT
|
|
||||||
return normal/length
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -2597,7 +2597,6 @@ class PatreonThanks(Scene):
|
|||||||
special_thanks.to_edge(UP)
|
special_thanks.to_edge(UP)
|
||||||
|
|
||||||
patreon_logo = PatreonLogo()
|
patreon_logo = PatreonLogo()
|
||||||
# patreon_logo.scale_to_fit_width(morty.get_width())
|
|
||||||
patreon_logo.next_to(morty, UP, buff = MED_LARGE_BUFF)
|
patreon_logo.next_to(morty, UP, buff = MED_LARGE_BUFF)
|
||||||
|
|
||||||
left_patrons = VGroup(*map(TextMobject,
|
left_patrons = VGroup(*map(TextMobject,
|
||||||
|
@ -318,7 +318,7 @@ def random_color():
|
|||||||
def straight_path(start_points, end_points, alpha):
|
def straight_path(start_points, end_points, alpha):
|
||||||
return interpolate(start_points, end_points, alpha)
|
return interpolate(start_points, end_points, alpha)
|
||||||
|
|
||||||
def path_along_arc(arc_angle):
|
def path_along_arc(arc_angle, axis = OUT):
|
||||||
"""
|
"""
|
||||||
If vect is vector from start to end, [vect[:,1], -vect[:,0]] is
|
If vect is vector from start to end, [vect[:,1], -vect[:,0]] is
|
||||||
perpendicualr to vect in the left direction.
|
perpendicualr to vect in the left direction.
|
||||||
@ -333,7 +333,7 @@ def path_along_arc(arc_angle):
|
|||||||
centers[:,i] += 0.5*b*vects[:,1-i]/np.tan(arc_angle/2)
|
centers[:,i] += 0.5*b*vects[:,1-i]/np.tan(arc_angle/2)
|
||||||
return centers + np.dot(
|
return centers + np.dot(
|
||||||
start_points-centers,
|
start_points-centers,
|
||||||
np.transpose(rotation_about_z(alpha*arc_angle))
|
np.transpose(rotation_matrix(alpha*arc_angle, axis))
|
||||||
)
|
)
|
||||||
return path
|
return path
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ from topics.numerals import *
|
|||||||
from topics.three_dimensions import *
|
from topics.three_dimensions import *
|
||||||
from scene import Scene
|
from scene import Scene
|
||||||
from scene.reconfigurable_scene import ReconfigurableScene
|
from scene.reconfigurable_scene import ReconfigurableScene
|
||||||
from camera import Camera, ShadingCamera
|
from camera import Camera
|
||||||
from mobject.svg_mobject import *
|
from mobject.svg_mobject import *
|
||||||
from mobject.tex_mobject import *
|
from mobject.tex_mobject import *
|
||||||
|
|
||||||
@ -148,9 +148,8 @@ class CheckOutMathologer(PiCreatureScene):
|
|||||||
logo.highlight(BLACK)
|
logo.highlight(BLACK)
|
||||||
return ApplyMethod(logo.restore)
|
return ApplyMethod(logo.restore)
|
||||||
|
|
||||||
class IntroduceStolenNecklaceProblem(Scene):
|
class IntroduceStolenNecklaceProblem(ThreeDScene):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"camera_class" : ShadingCamera,
|
|
||||||
"jewel_colors" : [BLUE, GREEN, WHITE, RED],
|
"jewel_colors" : [BLUE, GREEN, WHITE, RED],
|
||||||
"num_per_jewel" : [8, 10, 4, 6],
|
"num_per_jewel" : [8, 10, 4, 6],
|
||||||
"num_shuffles" : 1,
|
"num_shuffles" : 1,
|
||||||
@ -994,10 +993,7 @@ class FormLoopTransverseToEquator(ExternallyAnimatedScene):
|
|||||||
class AntipodalWalkAroundTransverseLoop(ExternallyAnimatedScene):
|
class AntipodalWalkAroundTransverseLoop(ExternallyAnimatedScene):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class MentionGenerality(TeacherStudentsScene):
|
class MentionGenerality(TeacherStudentsScene, ThreeDScene):
|
||||||
CONFIG = {
|
|
||||||
"camera_class" : ShadingCamera,
|
|
||||||
}
|
|
||||||
def construct(self):
|
def construct(self):
|
||||||
necklace = Necklace(width = SPACE_WIDTH)
|
necklace = Necklace(width = SPACE_WIDTH)
|
||||||
necklace.shift(2*UP)
|
necklace.shift(2*UP)
|
||||||
@ -1274,7 +1270,6 @@ class MentionMakingNecklaceProblemContinuous(TeacherStudentsScene):
|
|||||||
|
|
||||||
class MakeTwoJewelCaseContinuous(IntroduceStolenNecklaceProblem):
|
class MakeTwoJewelCaseContinuous(IntroduceStolenNecklaceProblem):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"camera_class" : ShadingCamera,
|
|
||||||
"jewel_colors" : [BLUE, GREEN],
|
"jewel_colors" : [BLUE, GREEN],
|
||||||
"num_per_jewel" : [8, 10],
|
"num_per_jewel" : [8, 10],
|
||||||
"random_seed" : 2,
|
"random_seed" : 2,
|
||||||
@ -2170,9 +2165,8 @@ class NecklaceDivisionSphereAssociation(ChoicesInNecklaceCutting):
|
|||||||
class SimpleRotatingSphereWithAntipodes(ExternallyAnimatedScene):
|
class SimpleRotatingSphereWithAntipodes(ExternallyAnimatedScene):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class TotalLengthOfEachJewelEquals(NecklaceDivisionSphereAssociation):
|
class TotalLengthOfEachJewelEquals(NecklaceDivisionSphereAssociation, ThreeDScene):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"camera_class" : ShadingCamera,
|
|
||||||
"random_seed" : 1,
|
"random_seed" : 1,
|
||||||
"thief_box_offset" : 1.2,
|
"thief_box_offset" : 1.2,
|
||||||
}
|
}
|
||||||
@ -2310,7 +2304,7 @@ class ExclaimBorsukUlam(TeacherStudentsScene):
|
|||||||
class ShowFunctionDiagram(TotalLengthOfEachJewelEquals, ReconfigurableScene):
|
class ShowFunctionDiagram(TotalLengthOfEachJewelEquals, ReconfigurableScene):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"necklace_center" : ORIGIN,
|
"necklace_center" : ORIGIN,
|
||||||
"camera_class" : ShadingCamera,
|
"camera_class" : ThreeDCamera,
|
||||||
"thief_box_offset" : 0.3,
|
"thief_box_offset" : 0.3,
|
||||||
"make_up_fair_division_indices" : False,
|
"make_up_fair_division_indices" : False,
|
||||||
}
|
}
|
||||||
@ -2407,7 +2401,7 @@ class ShowFunctionDiagram(TotalLengthOfEachJewelEquals, ReconfigurableScene):
|
|||||||
|
|
||||||
class JewelPairPlane(GraphScene):
|
class JewelPairPlane(GraphScene):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"camera_class" : ShadingCamera,
|
"camera_class" : ThreeDCamera,
|
||||||
"x_labeled_nums" : [],
|
"x_labeled_nums" : [],
|
||||||
"y_labeled_nums" : [],
|
"y_labeled_nums" : [],
|
||||||
"thief_number" : 1,
|
"thief_number" : 1,
|
||||||
@ -2639,7 +2633,7 @@ class MortyLookingAtRectangle(Scene):
|
|||||||
|
|
||||||
class RotatingThreeDSphereProjection(Scene):
|
class RotatingThreeDSphereProjection(Scene):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"camera_class" : ShadingCamera,
|
"camera_class" : ThreeDCamera,
|
||||||
}
|
}
|
||||||
def construct(self):
|
def construct(self):
|
||||||
sphere = VGroup(*[
|
sphere = VGroup(*[
|
||||||
@ -2659,8 +2653,21 @@ class FourDSphereProjectTo4D(ExternallyAnimatedScene):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Test(Scene):
|
||||||
|
CONFIG = {
|
||||||
|
"camera_class" : ThreeDCamera,
|
||||||
|
}
|
||||||
|
def construct(self):
|
||||||
|
randy = Randolph()
|
||||||
|
necklace = Necklace()
|
||||||
|
necklace.insert_n_anchor_points(20)
|
||||||
|
# necklace.apply_function(
|
||||||
|
# lambda (x, y, z) : x*RIGHT + (y + 0.1*x**2)*UP
|
||||||
|
# )
|
||||||
|
necklace.scale_to_fit_width(randy.get_width() + 1)
|
||||||
|
necklace.move_to(randy)
|
||||||
|
|
||||||
|
self.add(randy, necklace)
|
||||||
|
|
||||||
|
|
||||||
|
|
113
old_projects/three_dimensions.py
Normal file
113
old_projects/three_dimensions.py
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
import numpy as np
|
||||||
|
import itertools as it
|
||||||
|
|
||||||
|
from mobject import Mobject, Mobject1D, Mobject2D, Mobject
|
||||||
|
from geometry import Line
|
||||||
|
from helpers import *
|
||||||
|
|
||||||
|
class Stars(Mobject1D):
|
||||||
|
CONFIG = {
|
||||||
|
"stroke_width" : 1,
|
||||||
|
"radius" : SPACE_WIDTH,
|
||||||
|
"num_points" : 1000,
|
||||||
|
}
|
||||||
|
def generate_points(self):
|
||||||
|
radii, phis, thetas = [
|
||||||
|
scalar*np.random.random(self.num_points)
|
||||||
|
for scalar in [self.radius, np.pi, 2*np.pi]
|
||||||
|
]
|
||||||
|
self.add_points([
|
||||||
|
(
|
||||||
|
r * np.sin(phi)*np.cos(theta),
|
||||||
|
r * np.sin(phi)*np.sin(theta),
|
||||||
|
r * np.cos(phi)
|
||||||
|
)
|
||||||
|
for r, phi, theta in zip(radii, phis, thetas)
|
||||||
|
])
|
||||||
|
|
||||||
|
class CubeWithFaces(Mobject2D):
|
||||||
|
def generate_points(self):
|
||||||
|
self.add_points([
|
||||||
|
sgn * np.array(coords)
|
||||||
|
for x in np.arange(-1, 1, self.epsilon)
|
||||||
|
for y in np.arange(x, 1, self.epsilon)
|
||||||
|
for coords in it.permutations([x, y, 1])
|
||||||
|
for sgn in [-1, 1]
|
||||||
|
])
|
||||||
|
self.pose_at_angle()
|
||||||
|
self.set_color(BLUE)
|
||||||
|
|
||||||
|
def unit_normal(self, coords):
|
||||||
|
return np.array(map(lambda x : 1 if abs(x) == 1 else 0, coords))
|
||||||
|
|
||||||
|
class Cube(Mobject1D):
|
||||||
|
def generate_points(self):
|
||||||
|
self.add_points([
|
||||||
|
([a, b, c][p[0]], [a, b, c][p[1]], [a, b, c][p[2]])
|
||||||
|
for p in [(0, 1, 2), (2, 0, 1), (1, 2, 0)]
|
||||||
|
for a, b, c in it.product([-1, 1], [-1, 1], np.arange(-1, 1, self.epsilon))
|
||||||
|
])
|
||||||
|
self.pose_at_angle()
|
||||||
|
self.set_color(YELLOW)
|
||||||
|
|
||||||
|
class Octohedron(Mobject1D):
|
||||||
|
def generate_points(self):
|
||||||
|
x = np.array([1, 0, 0])
|
||||||
|
y = np.array([0, 1, 0])
|
||||||
|
z = np.array([0, 0, 1])
|
||||||
|
vertex_pairs = [(x+y, x-y), (x+y,-x+y), (-x-y,-x+y), (-x-y,x-y)]
|
||||||
|
vertex_pairs += [
|
||||||
|
(b[0]*x+b[1]*y, b[2]*np.sqrt(2)*z)
|
||||||
|
for b in it.product(*[(-1, 1)]*3)
|
||||||
|
]
|
||||||
|
for pair in vertex_pairs:
|
||||||
|
self.add_points(
|
||||||
|
Line(pair[0], pair[1], density = 1/self.epsilon).points
|
||||||
|
)
|
||||||
|
self.pose_at_angle()
|
||||||
|
self.set_color(MAROON_D)
|
||||||
|
|
||||||
|
class Dodecahedron(Mobject1D):
|
||||||
|
def generate_points(self):
|
||||||
|
phi = (1 + np.sqrt(5)) / 2
|
||||||
|
x = np.array([1, 0, 0])
|
||||||
|
y = np.array([0, 1, 0])
|
||||||
|
z = np.array([0, 0, 1])
|
||||||
|
v1, v2 = (phi, 1/phi, 0), (phi, -1/phi, 0)
|
||||||
|
vertex_pairs = [
|
||||||
|
(v1, v2),
|
||||||
|
(x+y+z, v1),
|
||||||
|
(x+y-z, v1),
|
||||||
|
(x-y+z, v2),
|
||||||
|
(x-y-z, v2),
|
||||||
|
]
|
||||||
|
five_lines_points = Mobject(*[
|
||||||
|
Line(pair[0], pair[1], density = 1.0/self.epsilon)
|
||||||
|
for pair in vertex_pairs
|
||||||
|
]).points
|
||||||
|
#Rotate those 5 edges into all 30.
|
||||||
|
for i in range(3):
|
||||||
|
perm = map(lambda j : j%3, range(i, i+3))
|
||||||
|
for b in [-1, 1]:
|
||||||
|
matrix = b*np.array([x[perm], y[perm], z[perm]])
|
||||||
|
self.add_points(np.dot(five_lines_points, matrix))
|
||||||
|
self.pose_at_angle()
|
||||||
|
self.set_color(GREEN)
|
||||||
|
|
||||||
|
class Sphere(Mobject2D):
|
||||||
|
def generate_points(self):
|
||||||
|
self.add_points([
|
||||||
|
(
|
||||||
|
np.sin(phi) * np.cos(theta),
|
||||||
|
np.sin(phi) * np.sin(theta),
|
||||||
|
np.cos(phi)
|
||||||
|
)
|
||||||
|
for phi in np.arange(self.epsilon, np.pi, self.epsilon)
|
||||||
|
for theta in np.arange(0, 2 * np.pi, 2 * self.epsilon / np.sin(phi))
|
||||||
|
])
|
||||||
|
self.set_color(BLUE)
|
||||||
|
|
||||||
|
def unit_normal(self, coords):
|
||||||
|
return np.array(coords) / np.linalg.norm(coords)
|
||||||
|
|
||||||
|
|
@ -424,8 +424,6 @@ class Scene(object):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,114 +1,91 @@
|
|||||||
import numpy as np
|
|
||||||
import itertools as it
|
|
||||||
|
|
||||||
from mobject import Mobject, Mobject1D, Mobject2D, Mobject
|
|
||||||
from geometry import Line
|
|
||||||
from helpers import *
|
from helpers import *
|
||||||
|
|
||||||
|
from scene import Scene
|
||||||
|
from camera import Camera
|
||||||
|
|
||||||
class Stars(Mobject1D):
|
class ThreeDCamera(Camera):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"stroke_width" : 1,
|
"sun_vect" : UP+LEFT,
|
||||||
"radius" : SPACE_WIDTH,
|
"shading_factor" : 0.5,
|
||||||
"num_points" : 1000,
|
|
||||||
}
|
}
|
||||||
def generate_points(self):
|
def __init__(self, *args, **kwargs):
|
||||||
radii, phis, thetas = [
|
Camera.__init__(self, *args, **kwargs)
|
||||||
scalar*np.random.random(self.num_points)
|
self.unit_sun_vect = self.sun_vect/np.linalg.norm(self.sun_vect)
|
||||||
for scalar in [self.radius, np.pi, 2*np.pi]
|
|
||||||
]
|
def display_multiple_vectorized_mobjects(self, vmobjects):
|
||||||
self.add_points([
|
def cmp_vmobs(vm1, vm2):
|
||||||
(
|
return cmp(vm1.get_center()[2], vm2.get_center()[2])
|
||||||
r * np.sin(phi)*np.cos(theta),
|
Camera.display_multiple_vectorized_mobjects(
|
||||||
r * np.sin(phi)*np.sin(theta),
|
self,
|
||||||
r * np.cos(phi)
|
sorted(vmobjects, cmp = cmp_vmobs)
|
||||||
)
|
)
|
||||||
for r, phi, theta in zip(radii, phis, thetas)
|
|
||||||
])
|
|
||||||
|
|
||||||
class CubeWithFaces(Mobject2D):
|
def get_stroke_color(self, vmobject):
|
||||||
def generate_points(self):
|
return Color(rgb = self.get_shaded_rgb(
|
||||||
self.add_points([
|
color_to_rgb(vmobject.get_stroke_color()),
|
||||||
sgn * np.array(coords)
|
normal_vect = self.get_unit_normal_vect(vmobject)
|
||||||
for x in np.arange(-1, 1, self.epsilon)
|
))
|
||||||
for y in np.arange(x, 1, self.epsilon)
|
|
||||||
for coords in it.permutations([x, y, 1])
|
def get_fill_color(self, vmobject):
|
||||||
for sgn in [-1, 1]
|
return Color(rgb = self.get_shaded_rgb(
|
||||||
])
|
color_to_rgb(vmobject.get_fill_color()),
|
||||||
self.pose_at_angle()
|
normal_vect = self.get_unit_normal_vect(vmobject)
|
||||||
self.set_color(BLUE)
|
))
|
||||||
|
|
||||||
|
def get_shaded_rgb(self, rgb, normal_vect):
|
||||||
|
brightness = np.dot(normal_vect, self.unit_sun_vect)
|
||||||
|
if brightness > 0:
|
||||||
|
alpha = self.shading_factor*brightness
|
||||||
|
return interpolate(rgb, np.ones(3), alpha)
|
||||||
|
else:
|
||||||
|
alpha = -self.shading_factor*brightness
|
||||||
|
return interpolate(rgb, np.zeros(3), alpha)
|
||||||
|
|
||||||
|
def get_unit_normal_vect(self, vmobject):
|
||||||
|
anchors = vmobject.get_anchors()
|
||||||
|
if len(anchors) < 3:
|
||||||
|
return OUT
|
||||||
|
normal = np.cross(anchors[1]-anchors[0], anchors[2]-anchors[1])
|
||||||
|
if normal[2] < 0:
|
||||||
|
normal = -normal
|
||||||
|
length = np.linalg.norm(normal)
|
||||||
|
if length == 0:
|
||||||
|
return OUT
|
||||||
|
return normal/length
|
||||||
|
|
||||||
|
|
||||||
|
class ThreeDScene(Scene):
|
||||||
|
CONFIG = {
|
||||||
|
"camera_class" : ThreeDCamera,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def unit_normal(self, coords):
|
|
||||||
return np.array(map(lambda x : 1 if abs(x) == 1 else 0, coords))
|
|
||||||
|
|
||||||
class Cube(Mobject1D):
|
|
||||||
def generate_points(self):
|
|
||||||
self.add_points([
|
|
||||||
([a, b, c][p[0]], [a, b, c][p[1]], [a, b, c][p[2]])
|
|
||||||
for p in [(0, 1, 2), (2, 0, 1), (1, 2, 0)]
|
|
||||||
for a, b, c in it.product([-1, 1], [-1, 1], np.arange(-1, 1, self.epsilon))
|
|
||||||
])
|
|
||||||
self.pose_at_angle()
|
|
||||||
self.set_color(YELLOW)
|
|
||||||
|
|
||||||
class Octohedron(Mobject1D):
|
|
||||||
def generate_points(self):
|
|
||||||
x = np.array([1, 0, 0])
|
|
||||||
y = np.array([0, 1, 0])
|
|
||||||
z = np.array([0, 0, 1])
|
|
||||||
vertex_pairs = [(x+y, x-y), (x+y,-x+y), (-x-y,-x+y), (-x-y,x-y)]
|
|
||||||
vertex_pairs += [
|
|
||||||
(b[0]*x+b[1]*y, b[2]*np.sqrt(2)*z)
|
|
||||||
for b in it.product(*[(-1, 1)]*3)
|
|
||||||
]
|
|
||||||
for pair in vertex_pairs:
|
|
||||||
self.add_points(
|
|
||||||
Line(pair[0], pair[1], density = 1/self.epsilon).points
|
|
||||||
)
|
|
||||||
self.pose_at_angle()
|
|
||||||
self.set_color(MAROON_D)
|
|
||||||
|
|
||||||
class Dodecahedron(Mobject1D):
|
|
||||||
def generate_points(self):
|
|
||||||
phi = (1 + np.sqrt(5)) / 2
|
|
||||||
x = np.array([1, 0, 0])
|
|
||||||
y = np.array([0, 1, 0])
|
|
||||||
z = np.array([0, 0, 1])
|
|
||||||
v1, v2 = (phi, 1/phi, 0), (phi, -1/phi, 0)
|
|
||||||
vertex_pairs = [
|
|
||||||
(v1, v2),
|
|
||||||
(x+y+z, v1),
|
|
||||||
(x+y-z, v1),
|
|
||||||
(x-y+z, v2),
|
|
||||||
(x-y-z, v2),
|
|
||||||
]
|
|
||||||
five_lines_points = Mobject(*[
|
|
||||||
Line(pair[0], pair[1], density = 1.0/self.epsilon)
|
|
||||||
for pair in vertex_pairs
|
|
||||||
]).points
|
|
||||||
#Rotate those 5 edges into all 30.
|
|
||||||
for i in range(3):
|
|
||||||
perm = map(lambda j : j%3, range(i, i+3))
|
|
||||||
for b in [-1, 1]:
|
|
||||||
matrix = b*np.array([x[perm], y[perm], z[perm]])
|
|
||||||
self.add_points(np.dot(five_lines_points, matrix))
|
|
||||||
self.pose_at_angle()
|
|
||||||
self.set_color(GREEN)
|
|
||||||
|
|
||||||
class Sphere(Mobject2D):
|
|
||||||
def generate_points(self):
|
|
||||||
self.add_points([
|
|
||||||
(
|
|
||||||
np.sin(phi) * np.cos(theta),
|
|
||||||
np.sin(phi) * np.sin(theta),
|
|
||||||
np.cos(phi)
|
|
||||||
)
|
|
||||||
for phi in np.arange(self.epsilon, np.pi, self.epsilon)
|
|
||||||
for theta in np.arange(0, 2 * np.pi, 2 * self.epsilon / np.sin(phi))
|
|
||||||
])
|
|
||||||
self.set_color(BLUE)
|
|
||||||
|
|
||||||
def unit_normal(self, coords):
|
|
||||||
return np.array(coords) / np.linalg.norm(coords)
|
|
||||||
|
|
||||||
|
|
Reference in New Issue
Block a user