manim icon indicating copy to clipboard operation
manim copied to clipboard

Slight offset in MoveAlongPath

Open jeremysalwen opened this issue 1 year ago • 4 comments

Description of bug / unexpected behavior

When using MoveAlongPath with a rotated object, a slight offset is introduced

Expected behavior

The object follows the line exactly, not with an offset.

How to reproduce the issue

Minimum Reproducible Code
%%manim -qm MowerAnimation

class MowerAnimation(Scene):
    def construct(self):
        # Create the mower as a small triangle
        mower = Triangle(color=GREEN, fill_opacity=1).scale(0.2)

        start_pos = np.array([-4, -3, 0])
        end_pos = np.array([-1, 4, 0])
        mower.move_to(start_pos)

        delta = end_pos - start_pos
        angle = np.arctan2(delta[0], delta[1])
        mower.rotate(-angle)

        path = Line(start_pos, end_pos)

        dashed_line = DashedLine(start_pos, end_pos)

        self.add(dashed_line)

        self.play(
            MoveAlongPath(mower, path, rate_func=linear),
            run_time=5
        )
        self.wait()

Additional media files

image

Logs

Terminal output
[09/19/24 21:12:51] DEBUG    Hashing ...                                                             [hashing.py](file:///usr/local/lib/python3.11/site-packages/manim/utils/hashing.py):[352](file:///usr/local/lib/python3.11/site-packages/manim/utils/hashing.py#352)

                    DEBUG    Hashing done in 0.132026 s.                                             [hashing.py](file:///usr/local/lib/python3.11/site-packages/manim/utils/hashing.py):[364](file:///usr/local/lib/python3.11/site-packages/manim/utils/hashing.py#364)

                    DEBUG    Hash generated :  2016333726_3528055951_4110290056                      [hashing.py](file:///usr/local/lib/python3.11/site-packages/manim/utils/hashing.py):[367](file:///usr/local/lib/python3.11/site-packages/manim/utils/hashing.py#367)

                    INFO     Animation 0 : Using cached data (hash :                           [cairo_renderer.py](file:///usr/local/lib/python3.11/site-packages/manim/renderer/cairo_renderer.py):[88](file:///usr/local/lib/python3.11/site-packages/manim/renderer/cairo_renderer.py#88)
                             2016333726_3528055951_4110290056)                                                     

                    DEBUG    List of the first few animation hashes of the scene:              [cairo_renderer.py](file:///usr/local/lib/python3.11/site-packages/manim/renderer/cairo_renderer.py):[97](file:///usr/local/lib/python3.11/site-packages/manim/renderer/cairo_renderer.py#97)
                             ['2016333726_3528055951_4110290056']                                                  

                                                                           

                    DEBUG    Animation with empty mobject                                          [animation.py](file:///usr/local/lib/python3.11/site-packages/manim/animation/animation.py):[175](file:///usr/local/lib/python3.11/site-packages/manim/animation/animation.py#175)

                    DEBUG    Hashing ...                                                             [hashing.py](file:///usr/local/lib/python3.11/site-packages/manim/utils/hashing.py):[352](file:///usr/local/lib/python3.11/site-packages/manim/utils/hashing.py#352)

                    DEBUG    Hashing done in 0.163328 s.                                             [hashing.py](file:///usr/local/lib/python3.11/site-packages/manim/utils/hashing.py):[364](file:///usr/local/lib/python3.11/site-packages/manim/utils/hashing.py#364)

                    DEBUG    Hash generated :  543634251_1704852926_3284192126                       [hashing.py](file:///usr/local/lib/python3.11/site-packages/manim/utils/hashing.py):[367](file:///usr/local/lib/python3.11/site-packages/manim/utils/hashing.py#367)

                    INFO     Animation 1 : Using cached data (hash :                           [cairo_renderer.py](file:///usr/local/lib/python3.11/site-packages/manim/renderer/cairo_renderer.py):[88](file:///usr/local/lib/python3.11/site-packages/manim/renderer/cairo_renderer.py#88)
                             543634251_1704852926_3284192126)                                                      

                    DEBUG    List of the first few animation hashes of the scene:              [cairo_renderer.py](file:///usr/local/lib/python3.11/site-packages/manim/renderer/cairo_renderer.py):[97](file:///usr/local/lib/python3.11/site-packages/manim/renderer/cairo_renderer.py#97)
                             ['2016333726_3528055951_4110290056',                                                  
                             '543634251_1704852926_3284192126']                                                    

                    INFO     Combining to Movie file.                                      [scene_file_writer.py](file:///usr/local/lib/python3.11/site-packages/manim/scene/scene_file_writer.py):[617](file:///usr/local/lib/python3.11/site-packages/manim/scene/scene_file_writer.py#617)

                    DEBUG    Partial movie files to combine (2 files):                     [scene_file_writer.py](file:///usr/local/lib/python3.11/site-packages/manim/scene/scene_file_writer.py):[561](file:///usr/local/lib/python3.11/site-packages/manim/scene/scene_file_writer.py#561)
                             ['/manim/media/videos/manim/720p30/partial_movie_files/MowerA                         
                             nimation/2016333726_3528055951_4110290056.mp4',                                       
                             '/manim/media/videos/manim/720p30/partial_movie_files/MowerAn                         
                             imation/543634251_1704852926_3284192126.mp4']                                         

                    INFO                                                                   [scene_file_writer.py](file:///usr/local/lib/python3.11/site-packages/manim/scene/scene_file_writer.py):[737](file:///usr/local/lib/python3.11/site-packages/manim/scene/scene_file_writer.py#737)
                             File ready at                                                                         
                             '/manim/media/videos/manim/720p30/MowerAnimation.mp4'                                 
                                                                                                                   

                    INFO     Rendered MowerAnimation                                                   [scene.py](file:///usr/local/lib/python3.11/site-packages/manim/scene/scene.py):[247](file:///usr/local/lib/python3.11/site-packages/manim/scene/scene.py#247)
                             Played 2 animations

System specifications

System Details ``` https://notebooks.gesis.org/binder/jupyter/user/manimcommunity-jupyter_examples-xz4gvrcr/notebooks/First%20Steps%20with%20Manim.ipynb ```

jeremysalwen avatar Sep 19 '24 21:09 jeremysalwen

It's not a bug, it's a feature. In Manim an object's position is generally identified by the center point of a rectangular bounding box around the object. This center point does not coincide with the mid-point of your rotated triangle though.

class MowerAnimation(Scene):
    def construct(self):
        # Create the mower as a small triangle
        mower = Triangle(color=GREEN, fill_opacity=0.5).scale(0.2).scale(3)

        start_pos = np.array([-4, -3, 0])
        end_pos = np.array([-1, 4, 0])
        mower.move_to(start_pos)

        delta = end_pos - start_pos
        angle = np.arctan2(delta[0], delta[1])
        mower.rotate(-angle)

        bbox = always_redraw(lambda:
            VGroup(
                Polygon(*[mower.get_critical_point(p) for p in (UR,UL,DL,DR)],stroke_width=1,stroke_color=YELLOW),
                Line(mower.get_critical_point(DOWN),mower.get_critical_point(UP),stroke_width=1,color=YELLOW),
                Line(mower.get_critical_point(LEFT),mower.get_critical_point(RIGHT),stroke_width=1,color=YELLOW),
            )
        )
        self.add(bbox)

        path = Line(start_pos, end_pos)

        dashed_line = DashedLine(start_pos, end_pos)

        self.add(dashed_line)

        self.play(
            MoveAlongPath(mower, path, rate_func=linear),
            run_time=5
        )
        self.wait()

https://github.com/user-attachments/assets/c0641b87-c57a-4911-8bc4-2d1a1e49acf0

How to change this?

  • use always_redraw or updater functions to run along the line rather than MoveAlongPath
  • or calculate the actual offset between the two centers, add an invisible, shifted path which you use for the MoveAlongPath
  • or create a VGroup which contains a larger object (e.g. a square or circle) than your triangle, place your triangle in the VGroup so that the mid-point of the triangle coincides with the bounding box of the complete VGroup

Somehow I was most curious to try out my third idea there:

class MowerAnimation(Scene):
    def construct(self):
        # Create the mower as a small triangle
        mower = VGroup(
            Square(stroke_opacity=0.2, fill_opacity=0)
        )
        tri = Triangle(color=GREEN, fill_opacity=0.5).scale(0.2)

        start_pos = np.array([-4, -3, 0])
        end_pos = np.array([-1, 4, 0])
        mower.move_to(start_pos)

        delta = end_pos - start_pos
        angle = np.arctan2(delta[0], delta[1])
        tri.rotate(-angle).shift(mower.get_center()-tri.get_center_of_mass())
        mower += tri

        path = Line(start_pos, end_pos)

        dashed_line = DashedLine(start_pos, end_pos)

        self.add(dashed_line)

        self.play(
            MoveAlongPath(mower, path, rate_func=linear),
            run_time=5
        )
        self.wait()

https://github.com/user-attachments/assets/bdacd608-a30f-4dd6-99a8-3cf8c38b338e

uwezi avatar Sep 19 '24 23:09 uwezi

In case you intend to rotate your triangle more often in this script, then you should use tri.rotate(angle, about_point=tri.get_center_of_mass()) This will keep the center of mass of the triangle fixed inside the square and thus the VGroup and only rotate the triangle. Don't rotate the mower in this script.

uwezi avatar Sep 19 '24 23:09 uwezi

Thank you, this is very helpful!

jeremysalwen avatar Sep 20 '24 02:09 jeremysalwen

Thank you, this is very helpful!

you are welcome. Come over to Discord for more tips about Manim and the details about its workings: https://docs.manim.community/en/stable/faq/general.html?highlight=discord#where-can-i-find-more-resources-for-learning-manim

uwezi avatar Sep 20 '24 07:09 uwezi