mirror of
https://github.com/ManimCommunity/manim.git
synced 2026-06-22 10:01:47 +00:00
Merge bf3339fde2 into 0e83f4b09a
This commit is contained in:
commit
188c9508db
7 changed files with 107 additions and 83 deletions
|
|
@ -807,10 +807,11 @@ class Dot(Circle):
|
|||
point: Point3DLike = ORIGIN,
|
||||
radius: float = DEFAULT_DOT_RADIUS,
|
||||
stroke_width: float = 0,
|
||||
fill_opacity: float = 1.0,
|
||||
fill_opacity: float | None = None,
|
||||
color: ParsableManimColor = WHITE,
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
self.submobjects = []
|
||||
super().__init__(
|
||||
arc_center=point,
|
||||
radius=radius,
|
||||
|
|
|
|||
|
|
@ -127,7 +127,7 @@ class BackgroundRectangle(SurroundingRectangle):
|
|||
buff=buff,
|
||||
**kwargs,
|
||||
)
|
||||
self.original_fill_opacity: float = self.fill_opacity
|
||||
self.original_fill_opacity: float = self.get_fill_opacities()
|
||||
|
||||
def pointwise_become_partial(self, mobject: Mobject, a: Any, b: float) -> Self:
|
||||
self.set_fill(opacity=b * self.original_fill_opacity)
|
||||
|
|
|
|||
|
|
@ -227,6 +227,7 @@ class BarChart(Axes):
|
|||
bar_names
|
||||
A sequence of names for each bar. Does not have to match the length of ``values``.
|
||||
y_range
|
||||
Takes the form (min, max, stepsize)
|
||||
The y_axis range of values. If ``None``, the range will be calculated based on the
|
||||
min/max of ``values`` and the step will be calculated based on ``y_length``.
|
||||
x_length
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ class Mobject:
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
color: ParsableManimColor | list[ParsableManimColor] = WHITE,
|
||||
color: ParsableManimColor | list[ParsableManimColor] | None = WHITE,
|
||||
name: str | None = None,
|
||||
dim: int = 3,
|
||||
target: Mobject | None = None,
|
||||
|
|
@ -451,7 +451,9 @@ class Mobject:
|
|||
return result
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return str(self.name)
|
||||
if hasattr(self, "name"):
|
||||
return str(self.name)
|
||||
return str(self.__class__.__name__)
|
||||
|
||||
def reset_points(self) -> Self:
|
||||
"""Sets :attr:`points` to be an empty array."""
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ class DecimalNumber(VMobject, metaclass=ConvertToOpenGL):
|
|||
self.include_background_rectangle = include_background_rectangle
|
||||
self.edge_to_fix = edge_to_fix
|
||||
self._font_size = font_size
|
||||
self.fill_opacity = fill_opacity
|
||||
self.set_fill_opacity(fill_opacity)
|
||||
|
||||
self.initial_config = kwargs.copy()
|
||||
self.initial_config.update(
|
||||
|
|
@ -132,7 +132,6 @@ class DecimalNumber(VMobject, metaclass=ConvertToOpenGL):
|
|||
)
|
||||
|
||||
self._set_submobjects_from_number(number)
|
||||
self.init_colors()
|
||||
|
||||
@property
|
||||
def font_size(self) -> float:
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ __all__ = [
|
|||
import itertools as it
|
||||
import sys
|
||||
from collections.abc import Callable, Hashable, Iterable, Mapping, Sequence
|
||||
from typing import TYPE_CHECKING, Any, Literal
|
||||
from typing import TYPE_CHECKING, Any, Literal, cast
|
||||
|
||||
import numpy as np
|
||||
from PIL.Image import Image
|
||||
|
|
@ -39,6 +39,7 @@ from manim.utils.bezier import (
|
|||
)
|
||||
from manim.utils.color import BLACK, WHITE, ManimColor, ParsableManimColor
|
||||
from manim.utils.iterables import (
|
||||
listify,
|
||||
make_even,
|
||||
resize_array,
|
||||
stretch_array_to_length,
|
||||
|
|
@ -108,13 +109,14 @@ class VMobject(Mobject):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
color: ParsableManimColor | list[ParsableManimColor] | None = None,
|
||||
fill_color: ParsableManimColor | None = None,
|
||||
fill_opacity: float = 0.0,
|
||||
fill_opacity: float | None = None,
|
||||
stroke_color: ParsableManimColor | None = None,
|
||||
stroke_opacity: float = 1.0,
|
||||
stroke_opacity: float | None = None,
|
||||
stroke_width: float = DEFAULT_STROKE_WIDTH,
|
||||
background_stroke_color: ParsableManimColor | None = BLACK,
|
||||
background_stroke_opacity: float = 1.0,
|
||||
background_stroke_opacity: float | None = None,
|
||||
background_stroke_width: float = 0,
|
||||
sheen_factor: float = 0.0,
|
||||
joint_type: LineJointType | None = None,
|
||||
|
|
@ -130,14 +132,7 @@ class VMobject(Mobject):
|
|||
cap_style: CapStyleType = CapStyleType.AUTO,
|
||||
**kwargs: Any,
|
||||
):
|
||||
self.fill_opacity = fill_opacity
|
||||
self.stroke_opacity = stroke_opacity
|
||||
self.stroke_width = stroke_width
|
||||
if background_stroke_color is not None:
|
||||
self.background_stroke_color: ManimColor = ManimColor(
|
||||
background_stroke_color
|
||||
)
|
||||
self.background_stroke_opacity: float = background_stroke_opacity
|
||||
self.background_stroke_width: float = background_stroke_width
|
||||
self.sheen_factor: float = sheen_factor
|
||||
self.joint_type: LineJointType = (
|
||||
|
|
@ -159,17 +154,35 @@ class VMobject(Mobject):
|
|||
0, 1, n_points_per_cubic_curve
|
||||
)
|
||||
self.cap_style: CapStyleType = cap_style
|
||||
super().__init__(**kwargs)
|
||||
self.submobjects: list[VMobject]
|
||||
|
||||
# TODO: Find where color overwrites are happening and remove the color doubling
|
||||
# if "color" in kwargs:
|
||||
# fill_color = kwargs["color"]
|
||||
# stroke_color = kwargs["color"]
|
||||
# TODO: Refactor color initialization
|
||||
# This must be after init
|
||||
|
||||
self.submobjects: list[VMobject]
|
||||
# if fill_color is not None or stroke_color is not None:
|
||||
# color = None
|
||||
|
||||
if background_stroke_color is not None:
|
||||
self.background_stroke_color: ManimColor | list[ManimColor] = (
|
||||
ManimColor.parse(background_stroke_color)
|
||||
)
|
||||
if background_stroke_opacity is not None:
|
||||
self.background_stroke_color = self.background_stroke_color.opacity(
|
||||
background_stroke_opacity
|
||||
)
|
||||
|
||||
print("Before", color, fill_color, stroke_color)
|
||||
super().__init__(color=color, **kwargs)
|
||||
print("After", self.color, self.fill_color, self.stroke_color)
|
||||
|
||||
if fill_color is not None:
|
||||
self.fill_color = ManimColor.parse(fill_color)
|
||||
if fill_opacity is not None:
|
||||
self.fill_color = self.fill_color.opacity(fill_opacity)
|
||||
if stroke_color is not None:
|
||||
self.stroke_color = ManimColor.parse(stroke_color)
|
||||
if stroke_opacity is not None:
|
||||
self.stroke_color = self.stroke_color.opacity(stroke_opacity)
|
||||
|
||||
def _assert_valid_submobjects(self, submobjects: Iterable[VMobject]) -> Self:
|
||||
return self._assert_valid_submobjects_internal(submobjects, VMobject)
|
||||
|
|
@ -191,21 +204,9 @@ class VMobject(Mobject):
|
|||
|
||||
# Colors
|
||||
def init_colors(self, propagate_colors: bool = True) -> Self:
|
||||
self.set_fill(
|
||||
color=self.fill_color,
|
||||
opacity=self.fill_opacity,
|
||||
family=propagate_colors,
|
||||
)
|
||||
self.set_stroke(
|
||||
color=self.stroke_color,
|
||||
width=self.stroke_width,
|
||||
opacity=self.stroke_opacity,
|
||||
family=propagate_colors,
|
||||
)
|
||||
self.set_background_stroke(
|
||||
color=self.background_stroke_color,
|
||||
width=self.background_stroke_width,
|
||||
opacity=self.background_stroke_opacity,
|
||||
family=propagate_colors,
|
||||
)
|
||||
self.set_sheen(
|
||||
|
|
@ -221,9 +222,7 @@ class VMobject(Mobject):
|
|||
return self
|
||||
|
||||
def generate_rgbas_array(
|
||||
self,
|
||||
color: ParsableManimColor | Iterable[ManimColor] | None,
|
||||
opacity: float | Iterable[float],
|
||||
self, color: ParsableManimColor | Iterable[ManimColor] | None
|
||||
) -> FloatRGBA:
|
||||
"""
|
||||
First arg can be either a color, or a tuple/list of colors.
|
||||
|
|
@ -233,17 +232,10 @@ class VMobject(Mobject):
|
|||
will automatically be added for the gradient
|
||||
"""
|
||||
colors: list[ManimColor] = [
|
||||
ManimColor(c) if (c is not None) else BLACK for c in tuplify(color)
|
||||
ManimColor(c) if (c is not None) else BLACK
|
||||
for c in cast(tuple[ParsableManimColor, ...], tuplify(color))
|
||||
]
|
||||
opacities: list[float] = [
|
||||
o if (o is not None) else 0.0 for o in tuplify(opacity)
|
||||
]
|
||||
rgbas: FloatRGBA_Array = np.array(
|
||||
[
|
||||
c.to_rgba_with_alpha(o)
|
||||
for c, o in zip(*make_even(colors, opacities), strict=True)
|
||||
],
|
||||
)
|
||||
rgbas: FloatRGBA_Array = np.array([c.to_rgba() for c in colors])
|
||||
|
||||
sheen_factor = self.get_sheen_factor()
|
||||
if sheen_factor != 0 and len(rgbas) == 1:
|
||||
|
|
@ -257,9 +249,10 @@ class VMobject(Mobject):
|
|||
self,
|
||||
array_name: str,
|
||||
color: ParsableManimColor | Iterable[ManimColor] | None = None,
|
||||
opacity: float | None = None,
|
||||
) -> Self:
|
||||
rgbas = self.generate_rgbas_array(color, opacity)
|
||||
if color is None:
|
||||
return self
|
||||
rgbas = self.generate_rgbas_array(color)
|
||||
if not hasattr(self, array_name):
|
||||
setattr(self, array_name, rgbas)
|
||||
return self
|
||||
|
|
@ -273,15 +266,14 @@ class VMobject(Mobject):
|
|||
rgbas = stretch_array_to_length(rgbas, len(curr_rgbas))
|
||||
# Only update rgb if color was not None, and only
|
||||
# update alpha channel if opacity was passed in
|
||||
if color is not None:
|
||||
curr_rgbas[:, :3] = rgbas[:, :3]
|
||||
if opacity is not None:
|
||||
curr_rgbas[:, 3] = rgbas[:, 3]
|
||||
curr_rgbas[:, :4] = rgbas[:, :4]
|
||||
print(array_name, curr_rgbas)
|
||||
setattr(self, array_name, curr_rgbas)
|
||||
return self
|
||||
|
||||
def set_fill(
|
||||
self,
|
||||
color: ParsableManimColor | None = None,
|
||||
color: ParsableManimColor | list[ParsableManimColor] | None = None,
|
||||
opacity: float | None = None,
|
||||
family: bool = True,
|
||||
) -> Self:
|
||||
|
|
@ -320,23 +312,33 @@ class VMobject(Mobject):
|
|||
--------
|
||||
:meth:`~.VMobject.set_style`
|
||||
"""
|
||||
new_color: list[ManimColor] = listify(self.get_fill_color())
|
||||
if color is not None:
|
||||
new_color: list[ManimColor] = listify(ManimColor.parse(color))
|
||||
if opacity is not None:
|
||||
new_color = [c.opacity(opacity) for c in new_color]
|
||||
|
||||
if family:
|
||||
for submobject in self.submobjects:
|
||||
submobject.set_fill(color, opacity, family)
|
||||
self.update_rgbas_array("fill_rgbas", color, opacity)
|
||||
self.update_rgbas_array("fill_rgbas", new_color)
|
||||
self.fill_rgbas: FloatRGBA_Array
|
||||
if opacity is not None:
|
||||
self.fill_opacity = opacity
|
||||
return self
|
||||
|
||||
def set_stroke(
|
||||
self,
|
||||
color: ParsableManimColor = None,
|
||||
color: ParsableManimColor | list[ParsableManimColor] | None = None,
|
||||
width: float | None = None,
|
||||
opacity: float | None = None,
|
||||
background=False,
|
||||
family: bool = True,
|
||||
) -> Self:
|
||||
new_color: list[ManimColor] = listify(self.get_fill_color())
|
||||
if color is not None:
|
||||
new_color: list[ManimColor] = listify(ManimColor.parse(color))
|
||||
if opacity is not None:
|
||||
new_color = [c.opacity(opacity) for c in new_color]
|
||||
|
||||
if family:
|
||||
for submobject in self.submobjects:
|
||||
submobject.set_stroke(color, width, opacity, background, family)
|
||||
|
|
@ -348,16 +350,14 @@ class VMobject(Mobject):
|
|||
array_name = "stroke_rgbas"
|
||||
width_name = "stroke_width"
|
||||
opacity_name = "stroke_opacity"
|
||||
self.update_rgbas_array(array_name, color, opacity)
|
||||
|
||||
self.update_rgbas_array(array_name, new_color)
|
||||
if width is not None:
|
||||
setattr(self, width_name, width)
|
||||
if opacity is not None:
|
||||
setattr(self, opacity_name, opacity)
|
||||
if color is not None and background:
|
||||
if isinstance(color, (list, tuple)):
|
||||
self.background_stroke_color = ManimColor.parse(color)
|
||||
else:
|
||||
self.background_stroke_color = ManimColor(color)
|
||||
self.background_stroke_color = ManimColor.parse(color)
|
||||
return self
|
||||
|
||||
def set_cap_style(self, cap_style: CapStyleType) -> Self:
|
||||
|
|
@ -587,6 +587,10 @@ class VMobject(Mobject):
|
|||
"""
|
||||
return self.get_fill_opacities()[0]
|
||||
|
||||
def set_fill_opacity(self, opacity: float):
|
||||
self.fill_color = [x.opacity(opacity) for x in tuplify(self.fill_color)]
|
||||
return self
|
||||
|
||||
# TODO: Does this just do a copy?
|
||||
# TODO: I have the feeling that this function should not return None, does that have any usage ?
|
||||
def get_fill_colors(self) -> list[ManimColor | None]:
|
||||
|
|
|
|||
|
|
@ -166,7 +166,9 @@ class ManimColor:
|
|||
alpha: float = 1.0,
|
||||
) -> None:
|
||||
if value is None:
|
||||
self._internal_value = np.array((0, 0, 0, alpha), dtype=ManimColorDType)
|
||||
self._internal_value = np.array(
|
||||
(1.0, 1.0, 1.0, alpha), dtype=ManimColorDType
|
||||
)
|
||||
elif isinstance(value, ManimColor):
|
||||
# logger.info(
|
||||
# "ManimColor was passed another ManimColor. This is probably not what "
|
||||
|
|
@ -629,6 +631,39 @@ class ManimColor:
|
|||
new[-1] = alpha
|
||||
return self._construct_from_space(new)
|
||||
|
||||
@overload
|
||||
def opacity(self, opacity: float) -> ManimColor:
|
||||
"""Returns a new ManimColor with the same color and the given opacity
|
||||
|
||||
Parameters
|
||||
----------
|
||||
opacity : float
|
||||
The opacity for the new ManimColor
|
||||
|
||||
Returns
|
||||
-------
|
||||
ManimColor
|
||||
The new ManimColor object with changed opacity
|
||||
"""
|
||||
|
||||
@overload
|
||||
def opacity(self, opacity: None) -> float:
|
||||
"""Returns the opacity of the current ManimColor in a range from zero to one
|
||||
|
||||
Returns
|
||||
-------
|
||||
float
|
||||
The opacity of the ManimColor
|
||||
"""
|
||||
|
||||
def opacity(self, opacity=None):
|
||||
"""Returns a new ManimColor with the same color and a new opacity or changes the opacity"""
|
||||
if opacity is None:
|
||||
return self._internal_value[3]
|
||||
tmp = self._internal_value.copy()
|
||||
tmp[3] = opacity
|
||||
return ManimColor.parse(tmp)
|
||||
|
||||
def interpolate(self, other: Self, alpha: float) -> Self:
|
||||
"""Interpolate between the current and the given :class:`ManimColor`, and return
|
||||
the result.
|
||||
|
|
@ -744,24 +779,6 @@ class ManimColor:
|
|||
return dark
|
||||
return self._from_internal(BLACK._internal_value)
|
||||
|
||||
def opacity(self, opacity: float) -> Self:
|
||||
"""Create a new :class:`ManimColor` with the given opacity and the same color
|
||||
values as before.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
opacity
|
||||
The new opacity value to be used.
|
||||
|
||||
Returns
|
||||
-------
|
||||
ManimColor
|
||||
The new :class:`ManimColor` with the same color values and the new opacity.
|
||||
"""
|
||||
tmp = self._internal_space.copy()
|
||||
tmp[-1] = opacity
|
||||
return self._construct_from_space(tmp)
|
||||
|
||||
def into(self, class_type: type[ManimColorT]) -> ManimColorT:
|
||||
"""Convert the current color into a different colorspace given by ``class_type``,
|
||||
without changing the :attr:`_internal_value`.
|
||||
|
|
@ -965,7 +982,7 @@ class ManimColor:
|
|||
raise NotImplementedError
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"{self.__class__.__name__}('{self.to_hex()}')"
|
||||
return f"{self.__class__.__name__}('{self.to_hex(True)}')"
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"{self.to_hex()}"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue