How to create multiple traced paths around the surface of a sphere?

66 views Asked by At

I have the following (I'm new to Manim so sorry if this is a mess!):

from manim import *
import numpy as np

class Example_1_1(ThreeDScene):
    # Parametric sphere
    def func(self, u, v):
        return np.array([np.sin(u) * np.cos(v), np.sin(u) * np.sin(v), np.cos(u)])

    def construct(self):
        # Define axes
        axes = ThreeDAxes(
            x_range=[-2,2], 
            x_length=4,
            y_range=[-2,2],
            y_length=4,
            z_range=[-2,2],
            z_length=4,
            x_axis_config = {'include_ticks':False, 'include_tip':False},
            y_axis_config ={'include_ticks':False, 'include_tip':False},
            z_axis_config ={'include_ticks':False, 'include_tip':False}
        )
        z_line = Line3D(start=np.array([0,0,3]), end=np.array([0,0,-3]),color=YELLOW_A, thickness=0.005)

        # Define sphere
        surface = Surface(
            lambda u, v: axes.c2p(*self.func(u, v)),
            u_range=[0, np.pi],
            v_range=[0, 2*np.pi],
            resolution=30,
            fill_opacity=0.75,
            checkerboard_colors=False,
            fill_color=GRAY,
            stroke_opacity=0
        )

        # Set camera angle
        self.move_camera(phi=70 * DEGREES, theta=45 * DEGREES)

        # Define start point 1
        start_point_1 = Dot3D(point=axes.coords_to_point(1,0,0), color=BLACK)

        # Define end point 1
        end_point_1 = Dot3D(point=axes.coords_to_point(1,0,0), color=BLACK)

        # Define circle centre 1
        circle_center_1 = Dot3D(point=axes.coords_to_point(0, 0, 0), fill_opacity = 0, stroke_opacity=0)
        # Add path for Transform 1
        self.add(
            TracedPath(
                start_point_1.get_center, 
                stroke_color=WHITE
            )
        )

        # Add Transform circle centre 1
        self.add(circle_center_1)
        # Place z line in frame
        self.add(z_line)
        self.remove(z_line)
        # Add axes and sphere
        self.play(FadeIn(axes), Write(surface), run_time=0.5)
        self.wait()
        self.play(Indicate(z_line))
        self.play(FadeOut(axes))
        self.wait(2)
        # Play point 1
        self.play(FadeIn(start_point_1))
        self.wait(0.5)

        # Move point 1
        self.play(Transform(
                start_point_1,
                end_point_1,
                path_func=utils.paths.path_along_circles(2*PI, circle_center_1.get_center()),
                run_time=3
                )
        )
        self.wait(2)
        self.move_camera(phi=0 * DEGREES, theta=45 * DEGREES, run_time=2)
        self.wait(2)

Which shows the point (1,0,0) rotating about the z-axis through 2pi leaving behind the circular path. I want to do this for multiple points on the sphere and I don't know where to even start!

What I tried was to do exactly what I did for the point (1,0,0) and literally duplicate each line need for that part and change to values so it would do it for a different point. This did not work... it gave me a few points following small circular paths within the sphere.

1

There are 1 answers

0
spooleey On BEST ANSWER

I asked about that on the Manim discord and another user wrote this code that works, if it is of interest to others looking to do something similar!

from manim import *
import numpy as np

class Example_1_1(ThreeDScene):              
    def func(self, u, v):
        return np.array([np.sin(u) * np.cos(v), np.sin(u) * np.sin(v), np.cos(u)])
    def construct(self):
        ax = ThreeDAxes(
            x_range=[-2,2], 
            x_length=4,
            y_range=[-2,2],
            y_length=4,
            z_range=[-2,2],
            z_length=4,
            x_axis_config = {'include_ticks':False, 'include_tip':False},
            y_axis_config ={'include_ticks':False, 'include_tip':False},
            z_axis_config ={'include_ticks':False, 'include_tip':False}
        )
        # Define sphere
        surface = Surface(
            lambda u, v: ax.c2p(*self.func(u, v)),
            u_range=[0, np.pi],
            v_range=[0, 2*np.pi],
            resolution=30,
            fill_opacity=0.75,
            checkerboard_colors=False,
            fill_color=GRAY,
            stroke_opacity=0
        )
        self.move_camera(phi=70 * DEGREES, theta=45 * DEGREES)        
        self.play(FadeIn(ax), Write(surface), run_time=0.5)        
        points = []
        for _ in range(4):
            rand_v = np.random.uniform(-1, 1, 3)
            u_v = rand_v / np.linalg.norm(rand_v)
            points.append(Dot3D(u_v))     
        self.add(*[TracedPath(point.get_center, stroke_color=WHITE) for point in points])
        self.play(*[FadeIn(point) for point in points], run_time=0.5)
        self.wait(0.5)
        ani = []
        for start, end in zip(points, points):        
            ani.append(
                Transform(
                    start,
                    end,
                    path_func=utils.paths.path_along_circles(2*PI, ORIGIN),
                    run_time=3
                )
            )
        self.play(*ani, run_time=3)       
        self.wait(2)
        self.move_camera(phi=0 * DEGREES, theta=45 * DEGREES, run_time=2)