mirror of
https://github.com/3b1b/manim.git
synced 2025-07-28 20:43:56 +08:00
Merge branch '3b1b:master' into master
This commit is contained in:
@ -3,6 +3,7 @@ from __future__ import annotations
|
||||
import moderngl
|
||||
from colour import Color
|
||||
import OpenGL.GL as gl
|
||||
import math
|
||||
|
||||
import itertools as it
|
||||
|
||||
@ -27,13 +28,14 @@ class CameraFrame(Mobject):
|
||||
CONFIG = {
|
||||
"frame_shape": (FRAME_WIDTH, FRAME_HEIGHT),
|
||||
"center_point": ORIGIN,
|
||||
"focal_distance": 2,
|
||||
"focal_dist_to_height": 2,
|
||||
}
|
||||
|
||||
def init_uniforms(self) -> None:
|
||||
super().init_uniforms()
|
||||
# As a quaternion
|
||||
self.uniforms["orientation"] = Rotation.identity().as_quat()
|
||||
self.uniforms["focal_dist_to_height"] = self.focal_dist_to_height
|
||||
|
||||
def init_points(self) -> None:
|
||||
self.set_points([ORIGIN, LEFT, RIGHT, DOWN, UP])
|
||||
@ -56,7 +58,7 @@ class CameraFrame(Mobject):
|
||||
return self
|
||||
|
||||
def get_euler_angles(self):
|
||||
return self.get_orientation().as_euler("xzy")
|
||||
return self.get_orientation().as_euler("zxz")[::-1]
|
||||
|
||||
def get_inverse_camera_rotation_matrix(self):
|
||||
return self.get_orientation().as_matrix().T
|
||||
@ -73,11 +75,11 @@ class CameraFrame(Mobject):
|
||||
gamma: float | None = None,
|
||||
units: float = RADIANS
|
||||
):
|
||||
eulers = self.get_euler_angles() # phi, theta, gamma
|
||||
for i, var in enumerate([phi, theta, gamma]):
|
||||
eulers = self.get_euler_angles() # theta, phi, gamma
|
||||
for i, var in enumerate([theta, phi, gamma]):
|
||||
if var is not None:
|
||||
eulers[i] = var * units
|
||||
self.set_orientation(Rotation.from_euler('xzy', eulers))
|
||||
self.set_orientation(Rotation.from_euler("zxz", eulers[::-1]))
|
||||
return self
|
||||
|
||||
def reorient(
|
||||
@ -114,6 +116,14 @@ class CameraFrame(Mobject):
|
||||
self.rotate(dgamma, self.get_inverse_camera_rotation_matrix()[2])
|
||||
return self
|
||||
|
||||
def set_focal_distance(self, focal_distance: float):
|
||||
self.uniforms["focal_dist_to_height"] = focal_distance / self.get_height()
|
||||
return self
|
||||
|
||||
def set_field_of_view(self, field_of_view: float):
|
||||
self.uniforms["focal_dist_to_height"] = 2 * math.tan(field_of_view / 2)
|
||||
return self
|
||||
|
||||
def get_shape(self):
|
||||
return (self.get_width(), self.get_height())
|
||||
|
||||
@ -130,7 +140,10 @@ class CameraFrame(Mobject):
|
||||
return points[4, 1] - points[3, 1]
|
||||
|
||||
def get_focal_distance(self) -> float:
|
||||
return self.focal_distance * self.get_height()
|
||||
return self.uniforms["focal_dist_to_height"] * self.get_height()
|
||||
|
||||
def get_field_of_view(self) -> float:
|
||||
return 2 * math.atan(self.uniforms["focal_dist_to_height"] / 2)
|
||||
|
||||
def get_implied_camera_location(self) -> np.ndarray:
|
||||
to_camera = self.get_inverse_camera_rotation_matrix()[2]
|
||||
|
@ -206,6 +206,13 @@ class Cube(SGroup):
|
||||
return Square3D(resolution=self.square_resolution)
|
||||
|
||||
|
||||
class Prism(Cube):
|
||||
def __init__(self, width: float = 3.0, height: float = 2.0, depth: float = 1.0, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
for dim, value in enumerate([width, height, depth]):
|
||||
self.rescale_to_fit(value, dim, stretch=True)
|
||||
|
||||
|
||||
class VCube(VGroup):
|
||||
CONFIG = {
|
||||
"fill_color": BLUE_D,
|
||||
@ -213,18 +220,25 @@ class VCube(VGroup):
|
||||
"stroke_width": 0,
|
||||
"gloss": 0.5,
|
||||
"shadow": 0.5,
|
||||
"joint_type": "round",
|
||||
}
|
||||
|
||||
def __init__(self, side_length: int = 2, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
def __init__(self, side_length: float = 2.0, **kwargs):
|
||||
face = Square(side_length=side_length)
|
||||
face.get_triangulation()
|
||||
self.add(*Cube.square_to_cube_faces(face))
|
||||
super().__init__(*Cube.square_to_cube_faces(face), **kwargs)
|
||||
self.init_colors()
|
||||
self.set_joint_type(self.joint_type)
|
||||
self.apply_depth_test()
|
||||
self.refresh_unit_normal()
|
||||
|
||||
|
||||
class VPrism(VCube):
|
||||
def __init__(self, width: float = 3.0, height: float = 2.0, depth: float = 1.0, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
for dim, value in enumerate([width, height, depth]):
|
||||
self.rescale_to_fit(value, dim, stretch=True)
|
||||
|
||||
|
||||
class Dodecahedron(VGroup):
|
||||
CONFIG = {
|
||||
"fill_color": BLUE_E,
|
||||
@ -272,20 +286,9 @@ class Dodecahedron(VGroup):
|
||||
# self.add(pentagon2.copy().apply_matrix(matrix, about_point=ORIGIN))
|
||||
|
||||
|
||||
class Prism(Cube):
|
||||
CONFIG = {
|
||||
"dimensions": [3, 2, 1]
|
||||
}
|
||||
|
||||
def init_points(self) -> None:
|
||||
Cube.init_points(self)
|
||||
for dim, value in enumerate(self.dimensions):
|
||||
self.rescale_to_fit(value, dim, stretch=True)
|
||||
|
||||
|
||||
class Prismify(VGroup):
|
||||
CONFIG = {
|
||||
"apply_depth_test": True
|
||||
"apply_depth_test": True,
|
||||
}
|
||||
|
||||
def __init__(self, vmobject, depth=1.0, direction=IN, **kwargs):
|
||||
|
@ -341,6 +341,14 @@ class VMobject(Mobject):
|
||||
def get_flat_stroke(self) -> bool:
|
||||
return self.flat_stroke
|
||||
|
||||
def set_joint_type(self, joint_type: str, recurse: bool = True):
|
||||
for mob in self.get_family(recurse):
|
||||
mob.joint_type = joint_type
|
||||
return self
|
||||
|
||||
def get_joint_type(self) -> str:
|
||||
return self.joint_type
|
||||
|
||||
# Points
|
||||
def set_anchors_and_handles(
|
||||
self,
|
||||
|
@ -4,11 +4,13 @@ import math
|
||||
import operator as op
|
||||
from functools import reduce
|
||||
from typing import Callable, Iterable, Sequence
|
||||
import platform
|
||||
|
||||
import numpy as np
|
||||
import numpy.typing as npt
|
||||
from mapbox_earcut import triangulate_float32 as earcut
|
||||
from scipy.spatial.transform import Rotation
|
||||
from tqdm import tqdm as ProgressDisplay
|
||||
|
||||
from manimlib.constants import RIGHT
|
||||
from manimlib.constants import DOWN
|
||||
@ -414,7 +416,16 @@ def earclip_triangulation(verts: np.ndarray, ring_ends: list[int]) -> list:
|
||||
))
|
||||
|
||||
chilren = [[] for i in rings]
|
||||
for idx, i in enumerate(rings_sorted):
|
||||
ringenum = ProgressDisplay(
|
||||
enumerate(rings_sorted),
|
||||
total=len(rings),
|
||||
leave=False,
|
||||
ascii=True if platform.system() == 'Windows' else None,
|
||||
dynamic_ncols=True,
|
||||
desc="SVG Triangulation",
|
||||
delay=3,
|
||||
)
|
||||
for idx, i in ringenum:
|
||||
for j in rings_sorted[:idx][::-1]:
|
||||
if is_in_fast(i, j):
|
||||
chilren[j].append(i)
|
||||
|
Reference in New Issue
Block a user