mirror of
https://github.com/3b1b/manim.git
synced 2025-08-05 16:49:03 +00:00
commit
d683a5c04b
3 changed files with 127 additions and 20 deletions
|
@ -4778,7 +4778,8 @@ class HypersphereStereographicProjection(SpecialThreeDScene):
|
||||||
[-1, 1, 0, 0],
|
[-1, 1, 0, 0],
|
||||||
[0, 0, 1, 1],
|
[0, 0, 1, 1],
|
||||||
[0, 1, -1, 1],
|
[0, 1, -1, 1],
|
||||||
]
|
],
|
||||||
|
"unit_labels_scale_factor": 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
def construct(self):
|
def construct(self):
|
||||||
|
@ -4827,6 +4828,7 @@ class HypersphereStereographicProjection(SpecialThreeDScene):
|
||||||
return label
|
return label
|
||||||
|
|
||||||
label.add_updater(update_label)
|
label.add_updater(update_label)
|
||||||
|
self.pink_dot_label = label
|
||||||
|
|
||||||
def get_pq_point():
|
def get_pq_point():
|
||||||
point = self.project_quaternion(q_tracker.get_value())
|
point = self.project_quaternion(q_tracker.get_value())
|
||||||
|
@ -4841,9 +4843,12 @@ class HypersphereStereographicProjection(SpecialThreeDScene):
|
||||||
def get_pq_line():
|
def get_pq_line():
|
||||||
point = get_pq_point()
|
point = get_pq_point()
|
||||||
norm = get_norm(point)
|
norm = get_norm(point)
|
||||||
|
origin = self.axes.coords_to_point(0, 0, 0)
|
||||||
if norm > dot_radius:
|
if norm > dot_radius:
|
||||||
|
point -= origin
|
||||||
point *= (norm - dot_radius) / norm
|
point *= (norm - dot_radius) / norm
|
||||||
result = Line(ORIGIN, point)
|
point += origin
|
||||||
|
result = Line(origin, point)
|
||||||
result.set_stroke(width=1)
|
result.set_stroke(width=1)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
@ -5114,6 +5119,7 @@ class HypersphereStereographicProjection(SpecialThreeDScene):
|
||||||
labels = VGroup()
|
labels = VGroup()
|
||||||
for tex, coords, vect in tex_coords_vects:
|
for tex, coords, vect in tex_coords_vects:
|
||||||
label = TexMobject(tex)
|
label = TexMobject(tex)
|
||||||
|
label.scale(self.unit_labels_scale_factor)
|
||||||
label.rotate(90 * DEGREES, RIGHT)
|
label.rotate(90 * DEGREES, RIGHT)
|
||||||
label.next_to(c2p(*coords), vect, SMALL_BUFF)
|
label.next_to(c2p(*coords), vect, SMALL_BUFF)
|
||||||
labels.add(label)
|
labels.add(label)
|
||||||
|
@ -5333,10 +5339,12 @@ class RuleOfQuaternionMultiplication(HypersphereStereographicProjection):
|
||||||
def add_unit_labels(self):
|
def add_unit_labels(self):
|
||||||
labels = self.unit_labels = self.get_unit_labels()
|
labels = self.unit_labels = self.get_unit_labels()
|
||||||
one_label = TexMobject("1")
|
one_label = TexMobject("1")
|
||||||
|
one_label.scale(self.unit_labels_scale_factor)
|
||||||
one_label.set_shade_in_3d(True)
|
one_label.set_shade_in_3d(True)
|
||||||
one_label.rotate(90 * DEGREES, RIGHT)
|
one_label.rotate(90 * DEGREES, RIGHT)
|
||||||
one_label.next_to(ORIGIN, IN + RIGHT, SMALL_BUFF)
|
one_label.next_to(ORIGIN, IN + RIGHT, SMALL_BUFF)
|
||||||
self.add(labels, one_label)
|
labels.add(one_label)
|
||||||
|
self.add(labels)
|
||||||
|
|
||||||
def show_multiplication_by_i_on_circle_1i(self):
|
def show_multiplication_by_i_on_circle_1i(self):
|
||||||
m_tracker = self.multiplier_tracker
|
m_tracker = self.multiplier_tracker
|
||||||
|
@ -6420,27 +6428,95 @@ class QuaternionEndscreen(PatreonEndScreen):
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class Thumbnail(RuleOfQuaternionMultiplication):
|
class ThumbnailP1(RuleOfQuaternionMultiplication):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"three_d_axes_config": {
|
"three_d_axes_config": {
|
||||||
"num_axis_pieces": 20,
|
"num_axis_pieces": 20,
|
||||||
}
|
},
|
||||||
|
"unit_labels_scale_factor": 1.5,
|
||||||
|
"quaternion": [1, 0, 0, 0],
|
||||||
}
|
}
|
||||||
|
|
||||||
def construct(self):
|
def construct(self):
|
||||||
self.setup_all_trackers()
|
self.setup_all_trackers()
|
||||||
quat = normalize([-0.5, 0.5, -0.5, 0.5])
|
self.remove(self.pink_dot_label)
|
||||||
self.multiplier_tracker.set_value(quat)
|
q_tracker = self.q_tracker
|
||||||
self.q_tracker.set_value(quat)
|
m_tracker = self.multiplier_tracker
|
||||||
sphere = self.get_projected_sphere(0, solid=False)
|
|
||||||
# self.specially_color_sphere(sphere)
|
# quat = normalize([-0.5, 0.5, -0.5, 0.5])
|
||||||
# sphere.set_fill(opacity=0.5)
|
quat = normalize(self.quaternion)
|
||||||
sphere.set_fill_by_checkerboard(BLUE_E, BLUE, opacity=0.8)
|
m_tracker.set_value(quat)
|
||||||
for face in sphere:
|
q_tracker.set_value(quat)
|
||||||
|
proj_sphere = self.get_projected_sphere(0, solid=False)
|
||||||
|
# self.specially_color_sphere(proj_sphere)
|
||||||
|
proj_sphere.set_color_by_gradient(
|
||||||
|
BLUE, YELLOW
|
||||||
|
)
|
||||||
|
proj_sphere.set_stroke(WHITE)
|
||||||
|
proj_sphere.set_fill(opacity=0.4)
|
||||||
|
for i, face in enumerate(proj_sphere):
|
||||||
|
alpha = i / len(proj_sphere)
|
||||||
|
opacity = 0.7 * (1 - there_and_back(alpha))
|
||||||
|
face.set_fill(opacity=opacity)
|
||||||
|
|
||||||
|
# unit_sphere = self.get_projected_sphere(0, quaternion=[1, 0, 0, 0], solid=False)
|
||||||
|
# self.specially_color_sphere(unit_sphere)
|
||||||
|
# unit_sphere.set_stroke(width=0)
|
||||||
|
# proj_sphere.set_fill_by_checkerboard(BLUE_E, BLUE, opacity=0.8)
|
||||||
|
for face in proj_sphere:
|
||||||
face.points = face.points[::-1]
|
face.points = face.points[::-1]
|
||||||
|
max_r = np.max(np.apply_along_axis(get_norm, 1, face.points))
|
||||||
|
if max_r > 30:
|
||||||
|
face.fade(1)
|
||||||
|
|
||||||
|
for label in self.unit_labels:
|
||||||
|
label.set_shade_in_3d(False)
|
||||||
|
label.set_background_stroke(color=BLACK, width=2)
|
||||||
|
|
||||||
|
self.add(proj_sphere)
|
||||||
|
# self.add(unit_sphere)
|
||||||
|
|
||||||
|
for mobject in self.mobjects:
|
||||||
|
try:
|
||||||
|
mobject.shift(IN)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
|
||||||
self.set_camera_orientation(
|
self.set_camera_orientation(
|
||||||
phi=70 * DEGREES,
|
phi=70 * DEGREES,
|
||||||
theta=-110 * DEGREES,
|
theta=-110 * DEGREES,
|
||||||
)
|
)
|
||||||
self.add(sphere)
|
|
||||||
|
|
||||||
|
class ThumbnailP2(ThumbnailP1):
|
||||||
|
CONFIG = {
|
||||||
|
"quaternion": [0, 1, 0, 0],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class ThumbnailOverlay(Scene):
|
||||||
|
def construct(self):
|
||||||
|
title = TextMobject("Quaternions")
|
||||||
|
title.set_width(8)
|
||||||
|
title.to_edge(UP)
|
||||||
|
v_line = Line(DOWN, UP)
|
||||||
|
v_line.set_height(FRAME_HEIGHT)
|
||||||
|
|
||||||
|
title.set_background_stroke(color=BLACK, width=1)
|
||||||
|
|
||||||
|
rect = BackgroundRectangle(title[4:6])
|
||||||
|
rect.set_fill(opacity=1)
|
||||||
|
rect.stretch(0.9, 0)
|
||||||
|
rect.stretch(1.1, 1)
|
||||||
|
title.add_to_back(BackgroundRectangle(title[0]))
|
||||||
|
title.add_to_back(rect)
|
||||||
|
|
||||||
|
arrow = Arrow(LEFT, RIGHT)
|
||||||
|
arrow.scale(1.5)
|
||||||
|
arrow.tip.scale(2)
|
||||||
|
arrow.set_stroke(width=10)
|
||||||
|
arrow.set_color(YELLOW)
|
||||||
|
|
||||||
|
self.add(v_line)
|
||||||
|
self.add(arrow)
|
||||||
|
self.add(title)
|
||||||
|
|
|
@ -74,9 +74,11 @@ class ThreeDScene(Scene):
|
||||||
return moving_mobjects
|
return moving_mobjects
|
||||||
|
|
||||||
def add_fixed_orientation_mobjects(self, *mobjects, **kwargs):
|
def add_fixed_orientation_mobjects(self, *mobjects, **kwargs):
|
||||||
|
self.add(*mobjects)
|
||||||
self.camera.add_fixed_orientation_mobjects(*mobjects, **kwargs)
|
self.camera.add_fixed_orientation_mobjects(*mobjects, **kwargs)
|
||||||
|
|
||||||
def add_fixed_in_frame_mobjects(self, *mobjects):
|
def add_fixed_in_frame_mobjects(self, *mobjects):
|
||||||
|
self.add(*mobjects)
|
||||||
self.camera.add_fixed_in_frame_mobjects(*mobjects)
|
self.camera.add_fixed_in_frame_mobjects(*mobjects)
|
||||||
|
|
||||||
def remove_fixed_orientation_mobjects(self, *mobjects):
|
def remove_fixed_orientation_mobjects(self, *mobjects):
|
||||||
|
|
|
@ -7,13 +7,46 @@ from constants import TAU
|
||||||
from functools import reduce
|
from functools import reduce
|
||||||
from utils.iterables import adjacent_pairs
|
from utils.iterables import adjacent_pairs
|
||||||
|
|
||||||
# Matrix operations
|
|
||||||
|
|
||||||
|
|
||||||
def get_norm(vect):
|
def get_norm(vect):
|
||||||
return sum([x**2 for x in vect])**0.5
|
return sum([x**2 for x in vect])**0.5
|
||||||
|
|
||||||
|
|
||||||
|
# Quaternions
|
||||||
|
# TODO, implement quaternion type
|
||||||
|
|
||||||
|
|
||||||
|
def quaternion_mult(q1, q2):
|
||||||
|
w1, x1, y1, z1 = q1
|
||||||
|
w2, x2, y2, z2 = q2
|
||||||
|
return np.array([
|
||||||
|
w1 * w2 - x1 * x2 - y1 * y2 - z1 * z2,
|
||||||
|
w1 * x2 + x1 * w2 + y1 * z2 - z1 * y2,
|
||||||
|
w1 * y2 + y1 * w2 + z1 * x2 - x1 * z2,
|
||||||
|
w1 * z2 + z1 * w2 + x1 * y2 - y1 * x2,
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
def quaternion_from_angle_axis(angle, axis):
|
||||||
|
return np.append(
|
||||||
|
np.cos(angle / 2),
|
||||||
|
np.sin(angle / 2) * normalize(axis)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def quaternion_conjugate(quaternion):
|
||||||
|
result = np.array(quaternion)
|
||||||
|
result[1:] *= -1
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def rotate_vector(vector, angle, axis=OUT):
|
||||||
|
quat = quaternion_from_angle_axis(angle, axis)
|
||||||
|
quat_inv = quaternion_conjugate(quat)
|
||||||
|
product = reduce(quaternion_mult, [quat, vector, quat_inv])
|
||||||
|
return product[1:]
|
||||||
|
|
||||||
|
|
||||||
def thick_diagonal(dim, thickness=2):
|
def thick_diagonal(dim, thickness=2):
|
||||||
row_indices = np.arange(dim).repeat(dim).reshape((dim, dim))
|
row_indices = np.arange(dim).repeat(dim).reshape((dim, dim))
|
||||||
col_indices = np.transpose(row_indices)
|
col_indices = np.transpose(row_indices)
|
||||||
|
@ -64,10 +97,6 @@ def z_to_vector(vector):
|
||||||
return np.dot(rotation_about_z(theta), phi_down)
|
return np.dot(rotation_about_z(theta), phi_down)
|
||||||
|
|
||||||
|
|
||||||
def rotate_vector(vector, angle, axis=OUT):
|
|
||||||
return np.dot(rotation_matrix(angle, axis), vector)
|
|
||||||
|
|
||||||
|
|
||||||
def angle_between(v1, v2):
|
def angle_between(v1, v2):
|
||||||
return np.arccos(np.dot(
|
return np.arccos(np.dot(
|
||||||
v1 / get_norm(v1),
|
v1 / get_norm(v1),
|
||||||
|
|
Loading…
Add table
Reference in a new issue