diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..346b597 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,14 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Python Debugger: Module", + "type": "debugpy", + "request": "launch", + "module": "manim_algorithm.examples.node" + } + ] +} \ No newline at end of file diff --git a/manim_algorithm/examples/__init__.py b/manim_algorithm/examples/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/examples/array.py b/manim_algorithm/examples/array.py similarity index 100% rename from examples/array.py rename to manim_algorithm/examples/array.py diff --git a/examples/code.py b/manim_algorithm/examples/code.py similarity index 100% rename from examples/code.py rename to manim_algorithm/examples/code.py diff --git a/examples/node.py b/manim_algorithm/examples/node.py similarity index 55% rename from examples/node.py rename to manim_algorithm/examples/node.py index 0c66738..f5da108 100644 --- a/examples/node.py +++ b/manim_algorithm/examples/node.py @@ -1,16 +1,14 @@ import sys import os -sys.path.append(os.path.join(os.path.dirname(__file__), "..")) - from manim import * -from manim_algorithm.node import Node +from ..node import Node class NodeScene(Scene): def construct(self): - node_list = [Node(1, text_scale=2), Node(1.2, width=3), Node("abc", box_color=RED), Node(, box_type=Circle), Node(" ")] + node_list = [Node(1, text_scale=2), Node(1.2, width=3), Node("abc", box_color=RED), Node('a', box_type=Circle), Node(" ")] nodes_group = VGroup(*node_list).arrange() self.play(FadeIn(nodes_group)) self.wait(1) @@ -77,4 +75,64 @@ def construct(self): self.play( Node.SwapAndOverWrite(node1, node2), Node.SwapAndOverWrite(node3, node4, select_color=RED)) - self.wait(1) \ No newline at end of file + self.wait(1) + +class NodeMoveAndOverwriteWithColor(Scene): + + def construct(self): + node1 = Node(1) + node2 = Node(2).next_to(node1, RIGHT, buff=1) + self.play(FadeIn(node1, node2)) + + steps = [] + steps.append(Node.Select(node1, color=RED, opacity=0.5)) + + steps.extend([ + ApplyMethod(node1.move_to, node2), + AnimationGroup( + Node.UpdateValue(node2, node1.value), + FadeOut(node1) + ) + ]) + a = Succession(*steps) + self.play(a, lag_ratio=1, run_time=5) + print(self.mobjects) + self.wait(1) + +class NodeUpdateValue1(Scene): + + def construct(self): + node = Node(1) + self.play(FadeIn(node)) + self.play(Node.UpdateValue(node, 2)) + self.wait(1) + +class TestCombine(Scene): + + class CombinedText(VMobject): + + def __init__(self): + super().__init__() + self.t1 = Text("1") + self.t2 = Text("2") + self.add(self.t1, self.t2) + + def set_t1_color(self, color): + self.t1.color = color + + def construct(self): + obj = self.CombinedText() + self.play(Succession(*[ + FadeIn(obj), + obj.animate.set_t1_color(RED), + FadeOut(obj) + ])) + self.wait(1) + +if __name__ == "__main__": + with tempconfig({"quality": "medium_quality", "preview": False, "save_as_gif": True, "format": "gif"}): + # scene = NodeUpdateValue1() + # scene.render() + + scene = TestCombine() + scene.render() \ No newline at end of file diff --git a/manim_algorithm/node.py b/manim_algorithm/node.py index 8172930..e32f3c8 100644 --- a/manim_algorithm/node.py +++ b/manim_algorithm/node.py @@ -1,6 +1,7 @@ from typing import Self, Literal, TypeAlias from manim import * -from manim.typing import Point3D, Vector3D +from manim.typing import ManimFloat, Point3D, Vector3D +from manim.utils.color import ManimColor from .utils.numpy_helper import NumpyHelper NodeValue: TypeAlias = str | int | float | None @@ -67,26 +68,68 @@ def __init__( """ super().__init__(**kwargs) + self.set_box(box_type, width, box_color) + self.text_scale = text_scale + self.set_value(value) + self.width = width + + def set_box(self, box_type: NodeBoxType, width: float, color: ManimColor) -> Self: + """ + 设置节点的形状和颜色 - self.value = value + Args: + box_type (type): Node的形状,Square或Circle + width (float): Node的宽度 + color (ManimColor): Node的颜色 + Returns: + Node: 返回自身 + """ + if hasattr(self, 'box'): + self.remove(self.box) if box_type not in [Square, Circle]: raise ValueError("box_type must be Square or Circle") if box_type == Square: self.box = Square(width) elif box_type == Circle: self.box = Circle(width / 2) - self.box.set_color(box_color) - self.text_scale = text_scale - self.text = self.generate_text_by_value(self.value) - self.width = width - # 注意,box应该在text下边,所以先加box再加text - self.add(self.box, self.text) + self.box.set_color(color) + self.add(self.box) + return self - def generate_text_by_value(self, value: NodeValue) -> Dot|Tex: + def get_box(self) -> Mobject: + return self.box + + def set_value(self, value: NodeValue) -> Self: + if hasattr(self, 'text'): + self.remove(self.text) + self.value = value if value is None or not str(value).strip(): - return Dot(radius=0) - return Tex(str(value)).scale(self.text_scale) + self.text = Dot(radius=0) + else: + self.text = Tex(str(value)).scale(self.text_scale) + self.text.move_to(self) + self.add(self.text) + return self + + def get_value(self) -> NodeValue: + return self.value + + def set_fill(self, + color: ParsableManimColor | None = None, + opacity: float | None = None, + family: bool = True, + ) -> Self: + super().set_fill(color, opacity, False) + if hasattr(self, 'box'): + self.box.set_fill(color, opacity, family) + return self + + def get_fill_color(self) -> ManimColor: + return self.box.get_fill_color() + + def get_fill_opacity(self) -> ManimFloat: + return self.box.get_fill_opacity() def get_slot(self, direction: Vector3D, index) -> Point3D: """ @@ -152,7 +195,8 @@ def __init__( color (ManimColor, optional): 填充的颜色. Defaults to RED. opacity (float, optional): 填充颜色的透明度. Defaults to 0.5. """ - super().__init__(AnimationGroup(*[node.box.animate.set_fill(color, opacity) for node in nodes]), **kwargs) + + super().__init__(AnimationGroup(*[node.animate.set_fill(color, opacity) for node in nodes]), **kwargs) class Unselect(Succession): @@ -161,7 +205,7 @@ def __init__(self, *nodes: List["Node"], **kwargs): 取消选择节点, 用于取消突出显示 具体的操作为设置节点的填充颜色为透明 """ - super().__init__(AnimationGroup(*[node.box.animate.set_fill(opacity=0) for node in nodes]), **kwargs) + super().__init__(AnimationGroup(*[node.animate.set_fill(node.get_fill_color(), 0) for node in nodes]), **kwargs) class UpdateValue(Succession): @@ -172,9 +216,8 @@ def __init__(self, node: "Node", value: NodeValue, **kwargs): Args: value (NodeValue): 新的值 """ - text = node.generate_text_by_value(value).move_to(node.text) - node.value = value - super().__init__(*[node.text.animate.become(text)], **kwargs) + super().__init__(*[node.animate.set_value(value)], **kwargs) + class MoveAndOverWrite(Succession): @@ -190,7 +233,8 @@ def __init__(self, node: "Node", target: "Node", select_color:ManimColor=None, s """ steps = [] if select_color is not None: - steps.append(Node.Select(node, select_color, select_opacity)) + steps.append(Node.Select(node, color=select_color, opacity=select_opacity)) + steps.extend([ node.animate.move_to(target), AnimationGroup( diff --git a/setup.py b/setup.py index 89b1e90..ccef5a0 100644 --- a/setup.py +++ b/setup.py @@ -11,7 +11,7 @@ setup( name='manim-algorithm', version=version, - packages=find_packages(exclude=["test", "test.*"]), + packages=find_packages(exclude=["test", "test.*", "examples", "examples.*"]), install_requires=[ "manim>=0.18.0" ],