mirror of
https://github.com/3b1b/manim.git
synced 2025-09-01 00:48:45 +00:00
Kill CONFIG in vectorized_mobject.py
This commit is contained in:
parent
97a5861ccf
commit
a715a5bc3f
1 changed files with 143 additions and 121 deletions
|
@ -42,57 +42,67 @@ from manimlib.shader_wrapper import ShaderWrapper
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Callable, Iterable, Sequence
|
||||
|
||||
from typing import Callable, Iterable, Sequence, Tuple
|
||||
import numpy.typing as npt
|
||||
from manimlib.constants import ManimColor
|
||||
|
||||
from manimlib.constants import ManimColor, np_vector
|
||||
|
||||
|
||||
class VMobject(Mobject):
|
||||
CONFIG = {
|
||||
"fill_color": None,
|
||||
"fill_opacity": 0.0,
|
||||
"stroke_color": None,
|
||||
"stroke_opacity": 1.0,
|
||||
"stroke_width": DEFAULT_STROKE_WIDTH,
|
||||
"draw_stroke_behind_fill": False,
|
||||
# Indicates that it will not be displayed, but
|
||||
# that it should count in parent mobject's path
|
||||
"pre_function_handle_to_anchor_scale_factor": 0.01,
|
||||
"make_smooth_after_applying_functions": False,
|
||||
"background_image_file": None,
|
||||
# This is within a pixel
|
||||
# TODO, do we care about accounting for
|
||||
# varying zoom levels?
|
||||
"tolerance_for_point_equality": 1e-8,
|
||||
"n_points_per_curve": 3,
|
||||
"long_lines": False,
|
||||
# For shaders
|
||||
"stroke_shader_folder": "quadratic_bezier_stroke",
|
||||
"fill_shader_folder": "quadratic_bezier_fill",
|
||||
# Could also be "bevel", "miter", "round"
|
||||
"joint_type": "auto",
|
||||
"flat_stroke": False,
|
||||
"render_primitive": moderngl.TRIANGLES,
|
||||
"fill_dtype": [
|
||||
('point', np.float32, (3,)),
|
||||
('unit_normal', np.float32, (3,)),
|
||||
('color', np.float32, (4,)),
|
||||
('vert_index', np.float32, (1,)),
|
||||
],
|
||||
"stroke_dtype": [
|
||||
("point", np.float32, (3,)),
|
||||
("prev_point", np.float32, (3,)),
|
||||
("next_point", np.float32, (3,)),
|
||||
('unit_normal', np.float32, (3,)),
|
||||
("stroke_width", np.float32, (1,)),
|
||||
("color", np.float32, (4,)),
|
||||
]
|
||||
}
|
||||
n_points_per_curve: int = 3
|
||||
stroke_shader_folder: str = "quadratic_bezier_stroke"
|
||||
fill_shader_folder: str = "quadratic_bezier_fill"
|
||||
fill_dtype: Sequence[Tuple[str, type, Tuple[int]]] = [
|
||||
('point', np.float32, (3,)),
|
||||
('unit_normal', np.float32, (3,)),
|
||||
('color', np.float32, (4,)),
|
||||
('vert_index', np.float32, (1,)),
|
||||
]
|
||||
stroke_dtype: Sequence[Tuple[str, type, Tuple[int]]] = [
|
||||
("point", np.float32, (3,)),
|
||||
("prev_point", np.float32, (3,)),
|
||||
("next_point", np.float32, (3,)),
|
||||
('unit_normal', np.float32, (3,)),
|
||||
("stroke_width", np.float32, (1,)),
|
||||
("color", np.float32, (4,)),
|
||||
]
|
||||
render_primitive: int = moderngl.TRIANGLES
|
||||
|
||||
pre_function_handle_to_anchor_scale_factor: float = 0.01
|
||||
make_smooth_after_applying_functions: bool = False
|
||||
# TODO, do we care about accounting for varying zoom levels?
|
||||
tolerance_for_point_equality: float = 1e-8
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
color: ManimColor = None, # If set, this will override stroke_color and fill_color
|
||||
fill_color: ManimColor = WHITE,
|
||||
fill_opacity: float = 0.0,
|
||||
stroke_color: ManimColor = GREY_C,
|
||||
stroke_opacity: float = 1.0,
|
||||
stroke_width: float = DEFAULT_STROKE_WIDTH,
|
||||
draw_stroke_behind_fill: bool = False,
|
||||
background_image_file: str | None = None,
|
||||
long_lines: bool = False,
|
||||
# Could also be "bevel", "miter", "round"
|
||||
joint_type: str = "auto",
|
||||
flat_stroke: bool = False,
|
||||
**kwargs
|
||||
):
|
||||
self.fill_color = color or fill_color
|
||||
self.fill_opacity = fill_opacity
|
||||
self.stroke_color = color or stroke_color
|
||||
self.stroke_opacity = stroke_opacity
|
||||
self.stroke_width = stroke_width
|
||||
self.draw_stroke_behind_fill = draw_stroke_behind_fill
|
||||
self.background_image_file = background_image_file
|
||||
self.long_lines = long_lines
|
||||
self.joint_type = joint_type
|
||||
self.flat_stroke = flat_stroke
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self.needs_new_triangulation = True
|
||||
self.triangulation = np.zeros(0, dtype='i4')
|
||||
|
||||
super().__init__(**kwargs)
|
||||
|
||||
def get_group_class(self):
|
||||
|
@ -108,32 +118,40 @@ class VMobject(Mobject):
|
|||
"unit_normal": np.zeros((1, 3))
|
||||
})
|
||||
|
||||
# These are here just to make type checkers happy
|
||||
def get_family(self, recurse: bool = True) -> list[VMobject]:
|
||||
return super().get_family(recurse)
|
||||
|
||||
def family_members_with_points(self) -> list[VMobject]:
|
||||
return super().family_members_with_points()
|
||||
|
||||
def replicate(self, n: int) -> VGroup:
|
||||
return super().replicate(n)
|
||||
|
||||
def get_grid(self, *args, **kwargs) -> VGroup:
|
||||
return super().get_grid(*args, **kwargs)
|
||||
|
||||
# Colors
|
||||
def init_colors(self):
|
||||
self.set_fill(
|
||||
color=self.fill_color or self.color,
|
||||
color=self.fill_color,
|
||||
opacity=self.fill_opacity,
|
||||
)
|
||||
self.set_stroke(
|
||||
color=self.stroke_color or self.color,
|
||||
color=self.stroke_color,
|
||||
width=self.stroke_width,
|
||||
opacity=self.stroke_opacity,
|
||||
background=self.draw_stroke_behind_fill,
|
||||
)
|
||||
self.set_gloss(self.gloss)
|
||||
self.set_flat_stroke(self.flat_stroke)
|
||||
self.color = self.get_color()
|
||||
return self
|
||||
|
||||
def set_rgba_array(
|
||||
self,
|
||||
rgba_array: npt.ArrayLike,
|
||||
name: str = None,
|
||||
rgba_array: np_vector,
|
||||
name: str | None = None,
|
||||
recurse: bool = False
|
||||
):
|
||||
if name is None:
|
||||
|
@ -147,7 +165,7 @@ class VMobject(Mobject):
|
|||
|
||||
def set_fill(
|
||||
self,
|
||||
color: ManimColor | Iterable[ManimColor] | None = None,
|
||||
color: ManimColor | Iterable[ManimColor] = None,
|
||||
opacity: float | Iterable[float] | None = None,
|
||||
recurse: bool = True
|
||||
):
|
||||
|
@ -156,7 +174,7 @@ class VMobject(Mobject):
|
|||
|
||||
def set_stroke(
|
||||
self,
|
||||
color: ManimColor | Iterable[ManimColor] | None = None,
|
||||
color: ManimColor | Iterable[ManimColor] = None,
|
||||
width: float | Iterable[float] | None = None,
|
||||
opacity: float | Iterable[float] | None = None,
|
||||
background: bool | None = None,
|
||||
|
@ -196,10 +214,10 @@ class VMobject(Mobject):
|
|||
self,
|
||||
fill_color: ManimColor | Iterable[ManimColor] | None = None,
|
||||
fill_opacity: float | Iterable[float] | None = None,
|
||||
fill_rgba: npt.ArrayLike | None = None,
|
||||
fill_rgba: np_vector | None = None,
|
||||
stroke_color: ManimColor | Iterable[ManimColor] | None = None,
|
||||
stroke_opacity: float | Iterable[float] | None = None,
|
||||
stroke_rgba: npt.ArrayLike | None = None,
|
||||
stroke_rgba: np_vector | None = None,
|
||||
stroke_width: float | Iterable[float] | None = None,
|
||||
stroke_background: bool = True,
|
||||
reflectiveness: float | None = None,
|
||||
|
@ -218,7 +236,7 @@ class VMobject(Mobject):
|
|||
)
|
||||
|
||||
if stroke_rgba is not None:
|
||||
mob.data['stroke_rgba'] = resize_with_interpolation(stroke_rgba, len(fill_rgba))
|
||||
mob.data['stroke_rgba'] = resize_with_interpolation(stroke_rgba, len(stroke_rgba))
|
||||
mob.set_stroke(
|
||||
width=stroke_width,
|
||||
background=stroke_background,
|
||||
|
@ -305,7 +323,7 @@ class VMobject(Mobject):
|
|||
for rgba in self.data['fill_rgba']
|
||||
]
|
||||
|
||||
def get_fill_opacities(self) -> np.ndarray:
|
||||
def get_fill_opacities(self) -> np_vector:
|
||||
return self.data['fill_rgba'][:, 3]
|
||||
|
||||
def get_stroke_colors(self) -> list[str]:
|
||||
|
@ -314,10 +332,10 @@ class VMobject(Mobject):
|
|||
for rgba in self.data['stroke_rgba']
|
||||
]
|
||||
|
||||
def get_stroke_opacities(self) -> np.ndarray:
|
||||
def get_stroke_opacities(self) -> np_vector:
|
||||
return self.data['stroke_rgba'][:, 3]
|
||||
|
||||
def get_stroke_widths(self) -> np.ndarray:
|
||||
def get_stroke_widths(self) -> np_vector:
|
||||
return self.data['stroke_width'][:, 0]
|
||||
|
||||
# TODO, it's weird for these to return the first of various lists
|
||||
|
@ -339,7 +357,7 @@ class VMobject(Mobject):
|
|||
def get_stroke_color(self) -> str:
|
||||
return self.get_stroke_colors()[0]
|
||||
|
||||
def get_stroke_width(self) -> float | np.ndarray:
|
||||
def get_stroke_width(self) -> float | np_vector:
|
||||
return self.get_stroke_widths()[0]
|
||||
|
||||
def get_stroke_opacity(self) -> float:
|
||||
|
@ -380,9 +398,9 @@ class VMobject(Mobject):
|
|||
# Points
|
||||
def set_anchors_and_handles(
|
||||
self,
|
||||
anchors1: np.ndarray,
|
||||
handles: np.ndarray,
|
||||
anchors2: np.ndarray
|
||||
anchors1: np_vector,
|
||||
handles: np_vector,
|
||||
anchors2: np_vector
|
||||
):
|
||||
assert(len(anchors1) == len(handles) == len(anchors2))
|
||||
nppc = self.n_points_per_curve
|
||||
|
@ -393,26 +411,26 @@ class VMobject(Mobject):
|
|||
self.set_points(new_points)
|
||||
return self
|
||||
|
||||
def start_new_path(self, point: np.ndarray):
|
||||
def start_new_path(self, point: np_vector):
|
||||
assert(self.get_num_points() % self.n_points_per_curve == 0)
|
||||
self.append_points([point])
|
||||
return self
|
||||
|
||||
def add_cubic_bezier_curve(
|
||||
self,
|
||||
anchor1: npt.ArrayLike,
|
||||
handle1: npt.ArrayLike,
|
||||
handle2: npt.ArrayLike,
|
||||
anchor2: npt.ArrayLike
|
||||
anchor1: np_vector,
|
||||
handle1: np_vector,
|
||||
handle2: np_vector,
|
||||
anchor2: np_vector
|
||||
):
|
||||
new_points = get_quadratic_approximation_of_cubic(anchor1, handle1, handle2, anchor2)
|
||||
self.append_points(new_points)
|
||||
|
||||
def add_cubic_bezier_curve_to(
|
||||
self,
|
||||
handle1: npt.ArrayLike,
|
||||
handle2: npt.ArrayLike,
|
||||
anchor: npt.ArrayLike
|
||||
handle1: np_vector,
|
||||
handle2: np_vector,
|
||||
anchor: np_vector
|
||||
):
|
||||
"""
|
||||
Add cubic bezier curve to the path.
|
||||
|
@ -426,14 +444,14 @@ class VMobject(Mobject):
|
|||
else:
|
||||
self.append_points(quadratic_approx)
|
||||
|
||||
def add_quadratic_bezier_curve_to(self, handle: np.ndarray, anchor: np.ndarray):
|
||||
def add_quadratic_bezier_curve_to(self, handle: np_vector, anchor: np_vector):
|
||||
self.throw_error_if_no_points()
|
||||
if self.has_new_path_started():
|
||||
self.append_points([handle, anchor])
|
||||
else:
|
||||
self.append_points([self.get_last_point(), handle, anchor])
|
||||
|
||||
def add_line_to(self, point: np.ndarray):
|
||||
def add_line_to(self, point: np_vector):
|
||||
end = self.get_points()[-1]
|
||||
alphas = np.linspace(0, 1, self.n_points_per_curve)
|
||||
if self.long_lines:
|
||||
|
@ -455,7 +473,7 @@ class VMobject(Mobject):
|
|||
self.append_points(points)
|
||||
return self
|
||||
|
||||
def add_smooth_curve_to(self, point: np.ndarray):
|
||||
def add_smooth_curve_to(self, point: np_vector):
|
||||
if self.has_new_path_started():
|
||||
self.add_line_to(point)
|
||||
else:
|
||||
|
@ -464,7 +482,7 @@ class VMobject(Mobject):
|
|||
self.add_quadratic_bezier_curve_to(new_handle, point)
|
||||
return self
|
||||
|
||||
def add_smooth_cubic_curve_to(self, handle: np.ndarray, point: np.ndarray):
|
||||
def add_smooth_cubic_curve_to(self, handle: np_vector, point: np_vector):
|
||||
self.throw_error_if_no_points()
|
||||
if self.get_num_points() == 1:
|
||||
new_handle = self.get_points()[-1]
|
||||
|
@ -475,10 +493,10 @@ class VMobject(Mobject):
|
|||
def has_new_path_started(self) -> bool:
|
||||
return self.get_num_points() % self.n_points_per_curve == 1
|
||||
|
||||
def get_last_point(self) -> np.ndarray:
|
||||
def get_last_point(self) -> np_vector:
|
||||
return self.get_points()[-1]
|
||||
|
||||
def get_reflection_of_last_handle(self) -> np.ndarray:
|
||||
def get_reflection_of_last_handle(self) -> np_vector:
|
||||
points = self.get_points()
|
||||
return 2 * points[-1] - points[-2]
|
||||
|
||||
|
@ -513,12 +531,12 @@ class VMobject(Mobject):
|
|||
vmob.set_points(np.vstack(new_points))
|
||||
return self
|
||||
|
||||
def add_points_as_corners(self, points: Iterable[np.ndarray]):
|
||||
def add_points_as_corners(self, points: Iterable[np_vector]):
|
||||
for point in points:
|
||||
self.add_line_to(point)
|
||||
return points
|
||||
|
||||
def set_points_as_corners(self, points: Iterable[np.ndarray]):
|
||||
def set_points_as_corners(self, points: Iterable[np_vector]):
|
||||
nppc = self.n_points_per_curve
|
||||
points = np.array(points)
|
||||
self.set_anchors_and_handles(*[
|
||||
|
@ -529,7 +547,7 @@ class VMobject(Mobject):
|
|||
|
||||
def set_points_smoothly(
|
||||
self,
|
||||
points: Iterable[np.ndarray],
|
||||
points: Iterable[np_vector],
|
||||
true_smooth: bool = False
|
||||
):
|
||||
self.set_points_as_corners(points)
|
||||
|
@ -584,7 +602,7 @@ class VMobject(Mobject):
|
|||
self.change_anchor_mode("jagged")
|
||||
return self
|
||||
|
||||
def add_subpath(self, points: Iterable[np.ndarray]):
|
||||
def add_subpath(self, points: Iterable[np_vector]):
|
||||
assert(len(points) % self.n_points_per_curve == 0)
|
||||
self.append_points(points)
|
||||
return self
|
||||
|
@ -600,11 +618,11 @@ class VMobject(Mobject):
|
|||
return self
|
||||
|
||||
#
|
||||
def consider_points_equals(self, p0: np.ndarray, p1: np.ndarray) -> bool:
|
||||
def consider_points_equals(self, p0: np_vector, p1: np_vector) -> bool:
|
||||
return get_norm(p1 - p0) < self.tolerance_for_point_equality
|
||||
|
||||
# Information about the curve
|
||||
def get_bezier_tuples_from_points(self, points: Sequence[np.ndarray]):
|
||||
def get_bezier_tuples_from_points(self, points: Sequence[np_vector]):
|
||||
nppc = self.n_points_per_curve
|
||||
remainder = len(points) % nppc
|
||||
points = points[:len(points) - remainder]
|
||||
|
@ -618,8 +636,8 @@ class VMobject(Mobject):
|
|||
|
||||
def get_subpaths_from_points(
|
||||
self,
|
||||
points: Sequence[np.ndarray]
|
||||
) -> list[Sequence[np.ndarray]]:
|
||||
points: Sequence[np_vector]
|
||||
) -> list[Sequence[np_vector]]:
|
||||
nppc = self.n_points_per_curve
|
||||
diffs = points[nppc - 1:-1:nppc] - points[nppc::nppc]
|
||||
splits = (diffs * diffs).sum(1) > self.tolerance_for_point_equality
|
||||
|
@ -636,28 +654,28 @@ class VMobject(Mobject):
|
|||
if (i2 - i1) >= nppc
|
||||
]
|
||||
|
||||
def get_subpaths(self) -> list[Sequence[np.ndarray]]:
|
||||
def get_subpaths(self) -> list[Sequence[np_vector]]:
|
||||
return self.get_subpaths_from_points(self.get_points())
|
||||
|
||||
def get_nth_curve_points(self, n: int) -> np.ndarray:
|
||||
def get_nth_curve_points(self, n: int) -> np_vector:
|
||||
assert(n < self.get_num_curves())
|
||||
nppc = self.n_points_per_curve
|
||||
return self.get_points()[nppc * n:nppc * (n + 1)]
|
||||
|
||||
def get_nth_curve_function(self, n: int) -> Callable[[float], np.ndarray]:
|
||||
def get_nth_curve_function(self, n: int) -> Callable[[float], np_vector]:
|
||||
return bezier(self.get_nth_curve_points(n))
|
||||
|
||||
def get_num_curves(self) -> int:
|
||||
return self.get_num_points() // self.n_points_per_curve
|
||||
|
||||
def quick_point_from_proportion(self, alpha: float) -> np.ndarray:
|
||||
def quick_point_from_proportion(self, alpha: float) -> np_vector:
|
||||
# Assumes all curves have the same length, so is inaccurate
|
||||
num_curves = self.get_num_curves()
|
||||
n, residue = integer_interpolate(0, num_curves, alpha)
|
||||
curve_func = self.get_nth_curve_function(n)
|
||||
return curve_func(residue)
|
||||
|
||||
def point_from_proportion(self, alpha: float) -> np.ndarray:
|
||||
def point_from_proportion(self, alpha: float) -> np_vector:
|
||||
if alpha <= 0:
|
||||
return self.get_start()
|
||||
elif alpha >= 1:
|
||||
|
@ -679,7 +697,7 @@ class VMobject(Mobject):
|
|||
residue = inverse_interpolate(partials[i - 1] / full, partials[i] / full, alpha)
|
||||
return self.get_nth_curve_function(i - 1)(residue)
|
||||
|
||||
def get_anchors_and_handles(self) -> list[np.ndarray]:
|
||||
def get_anchors_and_handles(self) -> list[np_vector]:
|
||||
"""
|
||||
returns anchors1, handles, anchors2,
|
||||
where (anchors1[i], handles[i], anchors2[i])
|
||||
|
@ -693,14 +711,14 @@ class VMobject(Mobject):
|
|||
for i in range(nppc)
|
||||
]
|
||||
|
||||
def get_start_anchors(self) -> np.ndarray:
|
||||
def get_start_anchors(self) -> np_vector:
|
||||
return self.get_points()[0::self.n_points_per_curve]
|
||||
|
||||
def get_end_anchors(self) -> np.ndarray:
|
||||
def get_end_anchors(self) -> np_vector:
|
||||
nppc = self.n_points_per_curve
|
||||
return self.get_points()[nppc - 1::nppc]
|
||||
|
||||
def get_anchors(self) -> np.ndarray:
|
||||
def get_anchors(self) -> np_vector:
|
||||
points = self.get_points()
|
||||
if len(points) == 1:
|
||||
return points
|
||||
|
@ -709,7 +727,7 @@ class VMobject(Mobject):
|
|||
self.get_end_anchors(),
|
||||
))))
|
||||
|
||||
def get_points_without_null_curves(self, atol: float = 1e-9) -> np.ndarray:
|
||||
def get_points_without_null_curves(self, atol: float = 1e-9) -> np_vector:
|
||||
nppc = self.n_points_per_curve
|
||||
points = self.get_points()
|
||||
distinct_curves = reduce(op.or_, [
|
||||
|
@ -729,7 +747,7 @@ class VMobject(Mobject):
|
|||
norms = np.array([get_norm(d) for d in diffs])
|
||||
return norms.sum()
|
||||
|
||||
def get_area_vector(self) -> np.ndarray:
|
||||
def get_area_vector(self) -> np_vector:
|
||||
# Returns a vector whose length is the area bound by
|
||||
# the polygon formed by the anchor points, pointing
|
||||
# in a direction perpendicular to the polygon according
|
||||
|
@ -749,7 +767,7 @@ class VMobject(Mobject):
|
|||
sum((p0[:, 0] + p1[:, 0]) * (p1[:, 1] - p0[:, 1])), # Add up (x1 + x2)*(y2 - y1)
|
||||
])
|
||||
|
||||
def get_unit_normal(self, recompute: bool = False) -> np.ndarray:
|
||||
def get_unit_normal(self, recompute: bool = False) -> np_vector:
|
||||
if not recompute:
|
||||
return self.data["unit_normal"][0]
|
||||
|
||||
|
@ -834,7 +852,7 @@ class VMobject(Mobject):
|
|||
mob.set_points(new_points)
|
||||
return self
|
||||
|
||||
def insert_n_curves_to_point_list(self, n: int, points: np.ndarray):
|
||||
def insert_n_curves_to_point_list(self, n: int, points: np_vector):
|
||||
nppc = self.n_points_per_curve
|
||||
if len(points) == 1:
|
||||
return np.repeat(points, nppc * n, 0)
|
||||
|
@ -936,7 +954,7 @@ class VMobject(Mobject):
|
|||
mob.needs_new_triangulation = True
|
||||
return self
|
||||
|
||||
def get_triangulation(self, normal_vector: np.ndarray | None = None):
|
||||
def get_triangulation(self, normal_vector: np_vector | None = None):
|
||||
# Figure out how to triangulate the interior to know
|
||||
# how to send the points as to the vertex shader.
|
||||
# First triangles come directly from the points
|
||||
|
@ -1005,7 +1023,7 @@ class VMobject(Mobject):
|
|||
return wrapper
|
||||
|
||||
@triggers_refreshed_triangulation
|
||||
def set_points(self, points: npt.ArrayLike):
|
||||
def set_points(self, points: np_vector):
|
||||
super().set_points(points)
|
||||
return self
|
||||
|
||||
|
@ -1018,7 +1036,7 @@ class VMobject(Mobject):
|
|||
@triggers_refreshed_triangulation
|
||||
def apply_function(
|
||||
self,
|
||||
function: Callable[[np.ndarray], np.ndarray],
|
||||
function: Callable[[np_vector], np_vector],
|
||||
make_smooth: bool = False,
|
||||
**kwargs
|
||||
):
|
||||
|
@ -1027,7 +1045,7 @@ class VMobject(Mobject):
|
|||
self.make_approximately_smooth()
|
||||
return self
|
||||
|
||||
def flip(self, axis: np.ndarray = UP, **kwargs):
|
||||
def flip(self, axis: np_vector = UP, **kwargs):
|
||||
super().flip(axis, **kwargs)
|
||||
self.refresh_unit_normal()
|
||||
self.refresh_triangulation()
|
||||
|
@ -1154,17 +1172,22 @@ class VGroup(VMobject):
|
|||
|
||||
|
||||
class VectorizedPoint(Point, VMobject):
|
||||
CONFIG = {
|
||||
"color": BLACK,
|
||||
"fill_opacity": 0,
|
||||
"stroke_width": 0,
|
||||
"artificial_width": 0.01,
|
||||
"artificial_height": 0.01,
|
||||
}
|
||||
|
||||
def __init__(self, location: np.ndarray = ORIGIN, **kwargs):
|
||||
Point.__init__(self, **kwargs)
|
||||
VMobject.__init__(self, **kwargs)
|
||||
def __init__(
|
||||
self,
|
||||
location: np.ndarray = ORIGIN,
|
||||
color: ManimColor = BLACK,
|
||||
fill_opacity: float = 0.0,
|
||||
stroke_width: float = 0.0,
|
||||
**kwargs
|
||||
):
|
||||
Point.__init__(self, location, **kwargs)
|
||||
VMobject.__init__(
|
||||
self,
|
||||
color=color,
|
||||
fill_opacity=fill_opacity,
|
||||
stroke_width=stroke_width,
|
||||
**kwargs
|
||||
)
|
||||
self.set_points(np.array([location]))
|
||||
|
||||
|
||||
|
@ -1179,23 +1202,22 @@ class CurvesAsSubmobjects(VGroup):
|
|||
|
||||
|
||||
class DashedVMobject(VMobject):
|
||||
CONFIG = {
|
||||
"num_dashes": 15,
|
||||
"positive_space_ratio": 0.5,
|
||||
"color": WHITE
|
||||
}
|
||||
|
||||
def __init__(self, vmobject: VMobject, **kwargs):
|
||||
def __init__(
|
||||
self,
|
||||
vmobject: VMobject,
|
||||
num_dashes: int = 15,
|
||||
positive_space_ratio: float = 0.5,
|
||||
**kwargs
|
||||
):
|
||||
super().__init__(**kwargs)
|
||||
num_dashes = self.num_dashes
|
||||
ps_ratio = self.positive_space_ratio
|
||||
|
||||
if num_dashes > 0:
|
||||
# End points of the unit interval for division
|
||||
alphas = np.linspace(0, 1, num_dashes + 1)
|
||||
|
||||
# This determines the length of each "dash"
|
||||
full_d_alpha = (1.0 / num_dashes)
|
||||
partial_d_alpha = full_d_alpha * ps_ratio
|
||||
partial_d_alpha = full_d_alpha * positive_space_ratio
|
||||
|
||||
# Rescale so that the last point of vmobject will
|
||||
# be the end of the last dash
|
||||
|
@ -1215,7 +1237,7 @@ class VHighlight(VGroup):
|
|||
self,
|
||||
vmobject: VMobject,
|
||||
n_layers: int = 5,
|
||||
color_bounds: tuple[ManimColor] = (GREY_C, GREY_E),
|
||||
color_bounds: Tuple[ManimColor] = (GREY_C, GREY_E),
|
||||
max_stroke_addition: float = 5.0,
|
||||
):
|
||||
outline = vmobject.replicate(n_layers)
|
||||
|
|
Loading…
Add table
Reference in a new issue