1
+ import abc
1
2
import typing as T
2
3
from collections import defaultdict
3
4
4
5
from manim import *
5
6
6
7
7
- class Activable ( VGroup ):
8
+ class ActivableMobject ( Group ):
8
9
def __init__ (
9
10
self ,
10
- inactive_vmobject : VMobject ,
11
- active_vmobject : VMobject ,
11
+ inactive_vmobject : Mobject ,
12
+ active_vmobject : Mobject ,
12
13
start_active : bool = False ,
13
14
activation_anim_run_time : float = 1.0 ,
14
15
deactivation_anim_run_time : float = 1.0 ,
15
16
group : T .Optional [int ] = None ,
16
17
) -> None :
17
- self .active_stroke_opacities = [x .stroke_opacity for x in active_vmobject .get_family ()]
18
- self .active_fill_opacities = [x .fill_opacity for x in active_vmobject .get_family ()]
19
- self .inactive_stroke_opacities = [x .stroke_opacity for x in inactive_vmobject .get_family ()]
20
- self .inactive_fill_opacities = [x .fill_opacity for x in inactive_vmobject .get_family ()]
21
-
18
+ self .is_active = start_active
19
+ self .activation_anim_run_time = activation_anim_run_time
20
+ self .deactivation_anim_run_time = deactivation_anim_run_time
21
+ self .group = group
22
22
super ().__init__ (
23
23
active_vmobject .copy () if start_active else inactive_vmobject .copy (),
24
24
active_vmobject .set_opacity (0 ),
@@ -34,14 +34,55 @@ def __init__(
34
34
self .group = group
35
35
36
36
@property
37
- def obj (self ) -> VMobject :
37
+ def obj (self ) -> Mobject :
38
38
return self [0 ]
39
39
40
- def get_activation_anim (self ) -> Animation :
40
+ @abc .abstractmethod
41
+ def _get_activation_anim (self ):
42
+ raise NotImplementedError
43
+
44
+ def activate (self ) -> Animation :
41
45
if self .is_active :
42
46
raise ValueError ("The object is already active." )
43
47
self .is_active = True
48
+ return self ._get_activation_anim ()
49
+
50
+ @abc .abstractmethod
51
+ def _get_deactivation_anim (self ):
52
+ raise NotImplementedError
53
+
54
+ def deactivate (self ) -> Animation :
55
+ if not self .is_active :
56
+ raise ValueError ("The object is already inactive." )
57
+ self .is_active = False
58
+ return self ._get_deactivation_anim ()
59
+
44
60
61
+ class VActivable (ActivableMobject ):
62
+ def __init__ (
63
+ self ,
64
+ inactive_vmobject : VMobject ,
65
+ active_vmobject : VMobject ,
66
+ start_active : bool = False ,
67
+ activation_anim_run_time : float = 1.0 ,
68
+ deactivation_anim_run_time : float = 1.0 ,
69
+ group : T .Optional [int ] = None ,
70
+ ) -> None :
71
+ self .active_stroke_opacities = [x .stroke_opacity for x in active_vmobject .get_family ()]
72
+ self .active_fill_opacities = [x .fill_opacity for x in active_vmobject .get_family ()]
73
+ self .inactive_stroke_opacities = [x .stroke_opacity for x in inactive_vmobject .get_family ()]
74
+ self .inactive_fill_opacities = [x .fill_opacity for x in inactive_vmobject .get_family ()]
75
+
76
+ super ().__init__ (
77
+ inactive_vmobject = inactive_vmobject ,
78
+ active_vmobject = active_vmobject ,
79
+ start_active = start_active ,
80
+ activation_anim_run_time = activation_anim_run_time ,
81
+ deactivation_anim_run_time = deactivation_anim_run_time ,
82
+ group = group ,
83
+ )
84
+
85
+ def _get_activation_anim (self ) -> Animation :
45
86
target = self .active_vmobject .copy ()
46
87
for subobj , stroke_opacity , fill_opacity in zip (
47
88
target .get_family (), self .active_stroke_opacities , self .active_fill_opacities
@@ -51,11 +92,7 @@ def get_activation_anim(self) -> Animation:
51
92
subobj .set_stroke (opacity = stroke_opacity , family = False , background = True )
52
93
return Transform (self .obj , target , run_time = self .activation_anim_run_time )
53
94
54
- def get_deactivation_anim (self ) -> Animation :
55
- if not self .is_active :
56
- raise ValueError ("The object is already inactive." )
57
- self .is_active = False
58
-
95
+ def _get_deactivation_anim (self ) -> Animation :
59
96
target = self .inactive_vmobject .copy ()
60
97
for subobj , stroke_opacity , fill_opacity in zip (
61
98
target .get_family (), self .inactive_stroke_opacities , self .inactive_fill_opacities
@@ -67,7 +104,7 @@ def get_deactivation_anim(self) -> Animation:
67
104
return Transform (self .obj , target , run_time = self .deactivation_anim_run_time )
68
105
69
106
70
- class AutoActivable ( Activable ):
107
+ class VAutoActivable ( VActivable ):
71
108
def __init__ (
72
109
self ,
73
110
vmobject : VMobject ,
@@ -78,6 +115,8 @@ def __init__(
78
115
scale_active : T .Optional [float ] = 1.1 ,
79
116
scale_about_point = None ,
80
117
scale_about_edge = LEFT ,
118
+ activation_anim_run_time : float = 1 ,
119
+ deactivation_anim_run_time : float = 1 ,
81
120
group : T .Optional [int ] = None ,
82
121
) -> None :
83
122
"""Activable component that automatically creates the active and inactive VMobjects.
@@ -91,6 +130,8 @@ def __init__(
91
130
scale_active (float): The scale of the active VMobject.
92
131
scale_about_point (np.ndarray): The point to scale about.
93
132
scale_about_edge (np.ndarray): The edge to scale about.
133
+ activation_anim_run_time (float): The run time of the activation animation.
134
+ deactivation_anim_run_time (float): The run time of the deactivation animation.
94
135
group (int): The group to which the object belongs.
95
136
"""
96
137
self .active_fill_opacity = active_fill_opacity
@@ -114,15 +155,80 @@ def __init__(
114
155
inactive_obj .set_fill (opacity = self .inactive_fill_opacity )
115
156
if self .inactive_stroke_opacity is not None :
116
157
inactive_obj .set_stroke (opacity = self .inactive_stroke_opacity )
117
- super ().__init__ (inactive_vmobject = inactive_obj , active_vmobject = active_obj , start_active = False , group = group )
158
+ super ().__init__ (
159
+ inactive_vmobject = inactive_obj ,
160
+ active_vmobject = active_obj ,
161
+ start_active = False ,
162
+ group = group ,
163
+ activation_anim_run_time = activation_anim_run_time ,
164
+ deactivation_anim_run_time = deactivation_anim_run_time ,
165
+ )
166
+
167
+
168
+ class ImageAutoActivable (ActivableMobject ):
169
+ def __init__ (
170
+ self ,
171
+ vmobject : Mobject ,
172
+ active_opacity : T .Optional [float ] = 1.0 ,
173
+ inactive_opacity : T .Optional [float ] = 0.35 ,
174
+ scale_active : T .Optional [float ] = 1.1 ,
175
+ scale_about_point = None ,
176
+ scale_about_edge = ORIGIN ,
177
+ activation_anim_run_time : float = 1.0 ,
178
+ deactivation_anim_run_time : float = 1.0 ,
179
+ group : T .Optional [int ] = None ,
180
+ ) -> None :
181
+ """Activable component that automatically creates the active and inactive Mobjects.
182
+
183
+ Args:
184
+ vmobject (Mobject): The object to activate or deactivate Mobject.
185
+ active_opacity (float): The fill opacity of the active Mobject.
186
+ inactive_opacity (float): The fill opacity of the inactive Mobject.
187
+ scale_active (float): The scale of the active Mobject.
188
+ scale_about_point (np.ndarray): The point to scale about.
189
+ scale_about_edge (np.ndarray): The edge to scale about.
190
+ activation_anim_run_time (float): The run time of the activation animation.
191
+ deactivation_anim_run_time (float): The run time of the deactivation animation.
192
+ group (int): The group to which the object belongs.
193
+ """
194
+ self .active_opacity = active_opacity
195
+ self .inactive_opacity = inactive_opacity
196
+ self .scale_active = scale_active
197
+ self .scale_about_point = scale_about_point
198
+ self .scale_about_edge = scale_about_edge
199
+
200
+ active_obj = vmobject .copy ()
201
+ if self .scale_active is not None :
202
+ active_obj .scale (self .scale_active , about_point = self .scale_about_point , about_edge = self .scale_about_edge )
203
+ if self .active_opacity is not None :
204
+ active_obj .set_opacity (self .active_opacity )
205
+
206
+ inactive_obj = vmobject .copy ()
207
+ if self .inactive_opacity is not None :
208
+ inactive_obj .set_opacity (self .inactive_opacity )
118
209
210
+ super ().__init__ (
211
+ inactive_vmobject = inactive_obj ,
212
+ active_vmobject = active_obj ,
213
+ start_active = False ,
214
+ activation_anim_run_time = activation_anim_run_time ,
215
+ deactivation_anim_run_time = deactivation_anim_run_time ,
216
+ group = group ,
217
+ )
119
218
120
- class VGroupActivable (VGroup ):
219
+ def _get_activation_anim (self ) -> Animation :
220
+ return self .obj .animate .set_opacity (self .active_opacity )
221
+
222
+ def _get_deactivation_anim (self ) -> Animation :
223
+ return self .obj .animate .set_opacity (self .inactive_opacity )
224
+
225
+
226
+ class GroupActivable (Group ):
121
227
def __init__ (
122
228
self ,
123
- * args : VMobject ,
229
+ * args : Mobject ,
124
230
anim_lag_ratio : float = 0 ,
125
- ** kwargs : VMobject ,
231
+ ** kwargs : Mobject ,
126
232
) -> None :
127
233
"""Group component that can activate a subset of its submobjects.
128
234
@@ -131,7 +237,14 @@ def __init__(
131
237
anim_lag_ratio (float): The lag ratio of the animation.
132
238
**kwargs: Keyword arguments to be passed to the VGroup.
133
239
"""
134
- args_activable = (AutoActivable (x ) if not isinstance (x , Activable ) else x for x in args )
240
+ args_activable = (
241
+ (
242
+ (VAutoActivable (x ) if isinstance (x , VMobject ) else ImageAutoActivable (x ))
243
+ if not isinstance (x , ActivableMobject )
244
+ else x
245
+ )
246
+ for x in args
247
+ )
135
248
super ().__init__ (* args_activable , ** kwargs )
136
249
137
250
self .anim_lag_ratio = anim_lag_ratio
@@ -146,7 +259,7 @@ def __init__(
146
259
if (None in groups ) and len (set (groups )) != 1 :
147
260
raise ValueError ("The groups must be specified for all or no bullets at all." )
148
261
149
- self .group2items : Dict [int , T .Set [Activable ]] = defaultdict (set )
262
+ self .group2items : Dict [int , T .Set [ActivableMobject ]] = defaultdict (set )
150
263
for i , obj in enumerate (self .submobjects ):
151
264
group = obj .group
152
265
if group is None :
@@ -177,14 +290,12 @@ def activate(self, indices: T.Union[int, T.Sequence[int]]) -> AnimationGroup:
177
290
for to_activate in indices :
178
291
if to_activate in self .previously_active_idxs :
179
292
continue
180
- anims .append (AnimationGroup (* (x .get_activation_anim () for x in self .group2items [to_activate ])))
293
+ anims .append (AnimationGroup (* (x .activate () for x in self .group2items [to_activate ])))
181
294
182
295
if self .previously_active_idxs :
183
296
for previously_active_idx in self .previously_active_idxs :
184
297
if previously_active_idx not in indices :
185
- anims .append (
186
- AnimationGroup (* (x .get_deactivation_anim () for x in self .group2items [previously_active_idx ]))
187
- )
298
+ anims .append (AnimationGroup (* (x .deactivate () for x in self .group2items [previously_active_idx ])))
188
299
189
300
self .previously_active_idxs = indices
190
301
0 commit comments