Merge branch '3b1b:master' into master

This commit is contained in:
YishiMichael
2022-03-30 22:02:23 +08:00
committed by GitHub
4 changed files with 58 additions and 23 deletions

View File

@ -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]

View File

@ -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):

View File

@ -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,

View File

@ -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)