Example #1
0
 def __init__(
     self,
     fill_opacity=0,
     stroke_width=3,
     length=DEFAULT_ARROW_TIP_LENGTH,
     start_angle=PI,
     **kwargs,
 ):
     self.start_angle = start_angle
     Circle.__init__(
         self, fill_opacity=fill_opacity, stroke_width=stroke_width, **kwargs
     )
     self.width = length
     self.stretch_to_fit_height(length)
Example #2
0
def test_animationbuilder_in_group(using_opengl_renderer):
    sqr = Square()
    circ = Circle()
    animation_group = AnimationGroup(
        sqr.animate.shift(DOWN).scale(2), FadeIn(circ))
    assert all(
        isinstance(anim, Animation) for anim in animation_group.animations)
    succession = Succession(sqr.animate.shift(DOWN).scale(2), FadeIn(circ))
    assert all(isinstance(anim, Animation) for anim in succession.animations)
Example #3
0
 def add_bases(self):
     """Adds the end caps of the cylinder."""
     color = self.color if config["renderer"] == "opengl" else self.fill_color
     opacity = self.opacity if config["renderer"] == "opengl" else self.fill_opacity
     self.base_top = Circle(
         radius=self.radius,
         color=color,
         fill_opacity=opacity,
         shade_in_3d=True,
         stroke_width=0,
     )
     self.base_top.shift(self.u_range[1] * IN)
     self.base_bottom = Circle(
         radius=self.radius,
         color=color,
         fill_opacity=opacity,
         shade_in_3d=True,
         stroke_width=0,
     )
     self.base_bottom.shift(self.u_range[0] * IN)
     self.add(self.base_top, self.base_bottom)
Example #4
0
    def __init__(self,
                 mobject: Mobject,
                 shape: Type = Rectangle,
                 fade_in=False,
                 fade_out=False,
                 time_width=0.3,
                 buff: float = SMALL_BUFF,
                 color: Color = YELLOW,
                 run_time=1,
                 stroke_width=DEFAULT_STROKE_WIDTH,
                 **kwargs):
        if shape is Rectangle:
            frame = SurroundingRectangle(
                mobject,
                color,
                buff,
                stroke_width=stroke_width,
            )
        elif shape is Circle:
            frame = Circle(color=color, stroke_width=stroke_width).surround(
                mobject,
                buffer_factor=1,
            )
            radius = frame.width / 2
            frame.scale((radius + buff) / radius)
        else:
            raise ValueError("shape should be either Rectangle or Circle.")

        if fade_in and fade_out:
            super().__init__(
                FadeIn(frame, run_time=run_time / 2),
                FadeOut(frame, run_time=run_time / 2),
                **kwargs,
            )
        elif fade_in:
            frame.reverse_direction()
            super().__init__(
                FadeIn(frame, run_time=run_time / 2),
                Uncreate(frame, run_time=run_time / 2),
                **kwargs,
            )
        elif fade_out:
            super().__init__(
                Create(frame, run_time=run_time / 2),
                FadeOut(frame, run_time=run_time / 2),
                **kwargs,
            )
        else:
            super().__init__(
                ShowPassingFlash(frame, time_width, run_time=run_time),
                **kwargs)
Example #5
0
def test_animationgroup_is_passing_remover_to_animations(
        animation_remover, animation_group_remover):
    scene = Scene()
    sqr_animation = Create(Square(), remover=animation_remover)
    circ_animation = Write(Circle(), remover=animation_remover)
    animation_group = AnimationGroup(sqr_animation,
                                     circ_animation,
                                     remover=animation_group_remover)

    scene.play(animation_group)
    scene.wait(0.1)

    assert sqr_animation.remover
    assert circ_animation.remover
Example #6
0
    def __init__(
        self,
        base_radius=1,
        height=1,
        direction=Z_AXIS,
        show_base=False,
        v_range=[0, TAU],
        u_min=0,
        checkerboard_colors=False,
        **kwargs,
    ):
        self.direction = direction
        self.theta = PI - np.arctan(base_radius / height)

        super().__init__(
            self.func,
            v_range=v_range,
            u_range=[u_min, np.sqrt(base_radius**2 + height**2)],
            checkerboard_colors=checkerboard_colors,
            **kwargs,
        )
        # used for rotations
        self._current_theta = 0
        self._current_phi = 0

        if show_base:
            self.base_circle = Circle(
                radius=base_radius,
                color=self.fill_color,
                fill_opacity=self.fill_opacity,
                stroke_width=0,
            )
            self.base_circle.shift(height * IN)
            self.add(self.base_circle)

        self._rotate_to_direction()
Example #7
0
def test_animationgroup_is_passing_remover_to_nested_animationgroups():
    scene = Scene()
    sqr_animation = Create(Square())
    circ_animation = Write(Circle(), remover=True)
    polygon_animation = Create(RegularPolygon(5))
    animation_group = AnimationGroup(
        AnimationGroup(sqr_animation, polygon_animation),
        circ_animation,
        remover=True,
    )

    scene.play(animation_group)
    scene.wait(0.1)

    assert sqr_animation.remover
    assert circ_animation.remover
    assert polygon_animation.remover
Example #8
0
    def _circle_to_mobject(self, circle_element: MinidomElement, style: dict):
        """Creates a Circle VMobject from a SVG <circle> command.

        Parameters
        ----------
        circle_element : :class:`minidom.Element`
            A SVG circle path command.

        style : :class:`dict`
            Style specification, using the SVG names for properties.

        Returns
        -------
        Circle
            A Circle VMobject
        """
        x, y, r = (self._attribute_to_float(circle_element.getAttribute(key))
                   if circle_element.hasAttribute(key) else 0.0
                   for key in ("cx", "cy", "r"))
        return Circle(radius=r,
                      **parse_style(style)).shift(x * RIGHT + y * DOWN)
Example #9
0
    def __init__(self, dark_theme: bool = True):
        super().__init__()

        logo_green = "#81b29a"
        logo_blue = "#454866"
        logo_red = "#e07a5f"
        m_height_over_anim_height = 0.75748

        self.font_color = "#ece6e2" if dark_theme else "#343434"
        self.scale_factor = 1

        self.M = MathTex(r"\mathbb{M}").scale(7).set_color(self.font_color)
        self.M.shift(2.25 * LEFT + 1.5 * UP)

        self.circle = Circle(color=logo_green, fill_opacity=1).shift(LEFT)
        self.square = Square(color=logo_blue, fill_opacity=1).shift(UP)
        self.triangle = Triangle(color=logo_red, fill_opacity=1).shift(RIGHT)
        self.shapes = VGroup(self.triangle, self.square, self.circle)
        self.add(self.shapes, self.M)
        self.move_to(ORIGIN)

        anim = VGroup()
        for i, ch in enumerate("anim"):
            tex = Tex(
                "\\textbf{" + ch + "}",
                tex_template=TexFontTemplates.gnu_freeserif_freesans,
            )
            if i != 0:
                tex.next_to(anim, buff=0.01)
            tex.align_to(self.M, DOWN)
            anim.add(tex)
        anim.set_color(self.font_color)
        anim.height = m_height_over_anim_height * self.M.height

        # Note: "anim" is only shown in the expanded state
        # and thus not yet added to the submobjects of self.
        self.anim = anim
Example #10
0
class Cylinder(Surface):
    """A cylinder, defined by its height, radius and direction,

    Examples
    ---------
    .. manim:: ExampleCylinder
        :save_last_frame:

        class ExampleCylinder(ThreeDScene):
            def construct(self):
                axes = ThreeDAxes()
                cylinder = Cylinder(radius=2, height=3)
                self.set_camera_orientation(phi=75 * DEGREES, theta=30 * DEGREES)
                self.add(axes, cylinder)

    Parameters
    ---------
    radius : :class:`float`
        The radius of the cylinder.
    height : :class:`float`
        The height of the cylinder.
    direction : :class:`numpy.array`
        The direction of the central axis of the cylinder.
    v_range : :class:`Sequence[float]`
        The height along the height axis (given by direction) to start and end on.
    show_ends : :class:`bool`
        Whether to show the end caps or not.
    """

    def __init__(
        self,
        radius=1,
        height=2,
        direction=Z_AXIS,
        v_range=[0, TAU],
        show_ends=True,
        resolution=(24, 24),
        **kwargs,
    ):
        self._height = height
        self.radius = radius
        super().__init__(
            self.func,
            resolution=resolution,
            u_range=[-self._height / 2, self._height / 2],
            v_range=v_range,
            **kwargs,
        )
        if show_ends:
            self.add_bases()
        self._current_phi = 0
        self._current_theta = 0
        self.set_direction(direction)

    def func(self, u, v):
        """Converts from cylindrical coordinates to cartesian.
        Parameters
        ---------
        u : :class:`float`
            The height.
        v : :class:`float`
            The azimuthal angle.
        """
        height = u
        phi = v
        r = self.radius
        return np.array([r * np.cos(phi), r * np.sin(phi), height])

    def add_bases(self):
        """Adds the end caps of the cylinder."""
        color = self.color if config["renderer"] == "opengl" else self.fill_color
        opacity = self.opacity if config["renderer"] == "opengl" else self.fill_opacity
        self.base_top = Circle(
            radius=self.radius,
            color=color,
            fill_opacity=opacity,
            shade_in_3d=True,
            stroke_width=0,
        )
        self.base_top.shift(self.u_range[1] * IN)
        self.base_bottom = Circle(
            radius=self.radius,
            color=color,
            fill_opacity=opacity,
            shade_in_3d=True,
            stroke_width=0,
        )
        self.base_bottom.shift(self.u_range[0] * IN)
        self.add(self.base_top, self.base_bottom)

    def _rotate_to_direction(self):
        x, y, z = self.direction

        r = np.sqrt(x**2 + y**2 + z**2)
        if r > 0:
            theta = np.arccos(z / r)
        else:
            theta = 0

        if x == 0:
            if y == 0:  # along the z axis
                phi = 0
            else:  # along the x axis
                phi = np.arctan(np.inf)
                if y < 0:
                    phi += PI
        else:
            phi = np.arctan(y / x)
        if x < 0:
            phi += PI

        # undo old rotation (in reverse direction)
        self.rotate(-self._current_phi, Z_AXIS, about_point=ORIGIN)
        self.rotate(-self._current_theta, Y_AXIS, about_point=ORIGIN)

        # do new rotation
        self.rotate(theta, Y_AXIS, about_point=ORIGIN)
        self.rotate(phi, Z_AXIS, about_point=ORIGIN)

        # store new values
        self._current_theta = theta
        self._current_phi = phi

    def set_direction(self, direction):
        # if get_norm(direction) is get_norm(self.direction):
        #     pass
        self.direction = direction
        self._rotate_to_direction()

    def get_direction(self):
        """Returns the direction of the central axis of the cylinder."""
        return self.direction
Example #11
0
class Cone(Surface):
    """A circular cone.
    Can be defined using 2 parameters: its height, and its base radius.
    The polar angle, theta, can be calculated using arctan(base_radius /
    height) The spherical radius, r, is calculated using the pythagorean
    theorem.

    Examples
    --------
    .. manim:: ExampleCone
        :save_last_frame:

        class ExampleCone(ThreeDScene):
            def construct(self):
                axes = ThreeDAxes()
                cone = Cone(direction=X_AXIS+Y_AXIS+2*Z_AXIS)
                self.set_camera_orientation(phi=5*PI/11, theta=PI/9)
                self.add(axes, cone)

    Parameters
    --------
    base_radius : :class:`float`
        The base radius from which the cone tapers.
    height : :class:`float`
        The height measured from the plane formed by the base_radius to the apex of the cone.
    direction : :class:`numpy.array`
        The direction of the apex.
    show_base : :class:`bool`
        Whether to show the base plane or not.
    v_range : :class:`Sequence[float]`
        The azimuthal angle to start and end at.
    u_min : :class:`float`
        The radius at the apex.
    checkerboard_colors : :class:`bool`
        Show checkerboard grid texture on the cone.
    """

    def __init__(
        self,
        base_radius=1,
        height=1,
        direction=Z_AXIS,
        show_base=False,
        v_range=[0, TAU],
        u_min=0,
        checkerboard_colors=False,
        **kwargs,
    ):
        self.direction = direction
        self.theta = PI - np.arctan(base_radius / height)

        super().__init__(
            self.func,
            v_range=v_range,
            u_range=[u_min, np.sqrt(base_radius**2 + height**2)],
            checkerboard_colors=checkerboard_colors,
            **kwargs,
        )
        # used for rotations
        self._current_theta = 0
        self._current_phi = 0

        if show_base:
            self.base_circle = Circle(
                radius=base_radius,
                color=self.fill_color,
                fill_opacity=self.fill_opacity,
                stroke_width=0,
            )
            self.base_circle.shift(height * IN)
            self.add(self.base_circle)

        self._rotate_to_direction()

    def func(self, u, v):
        """Converts from spherical coordinates to cartesian.
        Parameters
        ---------
        u : :class:`float`
            The radius.
        v : :class:`float`
            The azimuthal angle.
        """
        r = u
        phi = v
        return np.array(
            [
                r * np.sin(self.theta) * np.cos(phi),
                r * np.sin(self.theta) * np.sin(phi),
                r * np.cos(self.theta),
            ],
        )

    def _rotate_to_direction(self):
        x, y, z = self.direction

        r = np.sqrt(x**2 + y**2 + z**2)
        if r > 0:
            theta = np.arccos(z / r)
        else:
            theta = 0

        if x == 0:
            if y == 0:  # along the z axis
                phi = 0
            else:
                phi = np.arctan(np.inf)
                if y < 0:
                    phi += PI
        else:
            phi = np.arctan(y / x)
        if x < 0:
            phi += PI

        # Undo old rotation (in reverse order)
        self.rotate(-self._current_phi, Z_AXIS, about_point=ORIGIN)
        self.rotate(-self._current_theta, Y_AXIS, about_point=ORIGIN)

        # Do new rotation
        self.rotate(theta, Y_AXIS, about_point=ORIGIN)
        self.rotate(phi, Z_AXIS, about_point=ORIGIN)

        # Store values
        self._current_theta = theta
        self._current_phi = phi

    def set_direction(self, direction):
        self.direction = direction
        self._rotate_to_direction()

    def get_direction(self):
        return self.direction