Skip to content

Move mobject positioning methods into separate class - #4994

Open
GniLudio wants to merge 4 commits into
ManimCommunity:mainfrom
GniLudio:rework-positioning
Open

Move mobject positioning methods into separate class#4994
GniLudio wants to merge 4 commits into
ManimCommunity:mainfrom
GniLudio:rework-positioning

Conversation

@GniLudio

@GniLudio GniLudio commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Overview: What does this pull request change?

Moves the Mobject positioning methods into their own class.

Motivation and Explanation: Why and how do your changes improve the library?

  • Better separation of concerns
  • Cleans up implementations
  • Easier extensibility and maintainability
  • Performance improvements

Changes

  • Creates new class just for handling positioning
  • Streamlines structure of existing methods
  • Improves performance
  • Add setters for all parameters
  • All setters support passing another object as the value
  • Adds docstrings for all methods
  • Adjusts positionanal and keyword arguments
  • Deprecated unnecessary methods
    • should be discussed
  • All operations use all points now
    • Before some used get_all_points and some get_points_defining_boundary
    • Required updating a few graphical tests
  • Always uses 3D
  • Removed coor_mask parameter from move_to

Structure

Here is the full structure
  • Points
    • points, get_all_points
    • set_points, reset_points, reverse_points, repeat
    • get_num_points, has_points, has_no_points
  • Applying Functions
    • get_family
    • apply_(to_family|points_function|function|complex_function)
  • Transformations
    • translate, scale, stretch, rotate, apply_matrix
  • Position
    • (get|set)_position
      • (get|set)_(center|top|bottom|right|left|zenith|nadir)
        • center
    • (get|set)_coordinate
      • (get|set)_(x|y|z)
    • align_on_border, align_to
      • shift_onto_screen
    • apply_function_to_position, is_off_screen, get_center_of_mass, get_boundary_point
  • Size
    • (get|set)_dim_size
      • (get|set)_(width|height|depth)
      • (scale|stretch)_to_fit_dim
        • (scale|stretch)to_fit(width|height|depth)
  • Misc
    • flip, pose_at_angle, replace, surround
  • Aliases
    • shift -> translate
    • length_over_dim -> get_dim_size
    • get_critical_point, get_edge_center, get_corner -> get_position
    • move_to -> set_position
    • (get|set)_coord -> (get|set)_coordinate
    • to_corner, to_edge -> align_on_border
    • (width|height|depth) -> (get|set)_(width|height|depth)
  • Deprecated
    • apply_points_function_about_point -> apply_points_function
    • rescale_to_fit -> set_dim_size
    • stretch_about_point -> stretch
    • get_extremum_along_dim -> get_coordinate
    • match_* -> set_*
    • rotate_about_origin -> rotate
    • reduce_across_dimension
    • get_points_defining_boundary

Benchmark

I used randomized testing with 10-100k points (without submobjects) to benchmark and validate the changes.

Here are the benchmark results
10 100 1_000 10_000 100_000 Total Duration
align_on_border 1.6x 1.6x 1.5x 1.2x 1.7x 127 -> 77ms
align_to 1.9x 2.1x 2.3x 2.4x 3.7x 241 -> 68ms
center 1.8x 1.8x 1.5x 1.3x 1.6x 141 -> 91ms
depth (get) 0.58x 1.7x 9.1x 33.0x 22.2x 560 -> 26ms
depth (set) 1.5x 1.8x 3.3x 5.4x 5.2x 744 -> 146ms
flip 1.0x 1.0x 1.0x 1.0x 1.0x 179 -> 178ms
get_all_points 0.56x 0.57x 0.50x 0.57x 0.55x 0 -> 0ms
get_bottom 1.8x 1.9x 1.7x 1.2x 1.0x 44 -> 40ms
get_boundary_point 0.90x 0.92x 0.93x 0.94x 1.0x 21 -> 21ms
get_center 1.9x 2.0x 2.0x 1.3x 1.0x 53 -> 46ms
get_center_of_mass 2.2x 2.4x 2.0x 1.7x 1.1x 34 -> 28ms
get_coord 1.2x 1.3x 1.2x 1.2x 1.0x 18 -> 17ms
get_corner 2.0x 1.8x 1.7x 1.4x 1.1x 39 -> 34ms
get_critical_point 1.8x 1.9x 1.7x 1.3x 1.0x 36 -> 33ms
get_edge_center 1.9x 1.9x 1.7x 1.3x 1.0x 37 -> 33ms
get_extremum_along_dim 0.99x 1.0x 0.96x 1.0x 1.0x 21 -> 21ms
get_left 1.6x 1.9x 1.7x 1.3x 1.0x 45 -> 41ms
get_nadir 1.9x 1.8x 1.7x 1.3x 1.0x 45 -> 40ms
get_num_points 0.80x 0.91x 0.77x 0.74x 0.84x 0 -> 0ms
get_points_defining_boundary 0.55x 0.57x 0.49x 0.52x 0.60x 0 -> 1ms
get_right 1.9x 1.9x 1.7x 1.3x 1.0x 47 -> 42ms
get_top 1.9x 2.0x 1.7x 1.3x 1.1x 48 -> 43ms
get_x 1.5x 1.4x 1.3x 1.1x 1.0x 27 -> 26ms
get_y 1.4x 1.4x 1.3x 1.1x 1.0x 28 -> 27ms
get_z 1.4x 1.4x 1.3x 1.2x 1.0x 32 -> 30ms
get_zenith 2.0x 1.9x 1.7x 1.2x 1.1x 51 -> 45ms
has_no_points 1.1x 1.0x 1.0x 1.1x 1.1x 0 -> 0ms
has_points 0.92x 0.89x 0.85x 0.83x 0.98x 0 -> 0ms
height (get) 0.64x 1.9x 9.3x 36.1x 23.0x 542 -> 24ms
height (set) 1.5x 1.8x 3.2x 5.5x 5.3x 720 -> 140ms
is_off_screen 9.1x 8.7x 8.5x 6.0x 3.6x 134 -> 33ms
length_over_dim 0.67x 1.8x 9.9x 36.5x 22.6x 546 -> 24ms
match_coord 2.0x 1.9x 1.7x 1.3x 1.8x 112 -> 62ms
match_depth 1.4x 1.7x 3.7x 6.5x 6.1x 689 -> 115ms
match_dim_size 1.4x 1.7x 3.5x 6.7x 6.0x 698 -> 118ms
match_height 1.5x 1.7x 3.6x 6.7x 6.1x 695 -> 116ms
match_points 2.3x 2.7x 3.5x 2.9x 1.2x 13 -> 9ms
match_width 1.5x 1.7x 3.8x 6.7x 6.0x 710 -> 120ms
match_x 1.9x 2.0x 1.8x 1.3x 1.9x 117 -> 64ms
match_y 1.8x 1.6x 1.9x 1.3x 1.9x 120 -> 65ms
match_z 1.9x 1.9x 1.7x 1.3x 1.9x 116 -> 64ms
move_to 1.9x 1.7x 1.6x 1.3x 1.7x 129 -> 77ms
pose_at_angle 1.1x 1.0x 1.1x 1.0x 1.0x 174 -> 172ms
repeat 1.8x 2.2x 2.5x 3.6x 4.5x 778 -> 177ms
replace 1.9x 1.9x 2.5x 3.7x 4.2x 1281 -> 317ms
rescale_to_fit 1.1x 1.6x 3.7x 6.9x 6.2x 702 -> 115ms
reset_points 0.37x 0.54x 0.50x 0.41x 0.96x 8 -> 8ms
reverse_points 3.1x 11.4x 31.5x 42.4x 25.3x 2096 -> 80ms
rotate 1.1x 1.2x 1.0x 1.0x 0.99x 176 -> 176ms
rotate_about_origin 1.0x 1.0x 1.0x 1.0x 1.0x 172 -> 170ms
scale 1.3x 1.2x 1.2x 1.1x 1.5x 137 -> 94ms
scale_to_fit_depth 1.1x 1.6x 3.9x 6.5x 6.3x 719 -> 117ms
scale_to_fit_height 1.0x 1.5x 3.3x 7.0x 6.2x 731 -> 121ms
scale_to_fit_width 1.0x 1.5x 3.9x 7.2x 6.2x 715 -> 116ms
set_coord 1.4x 1.3x 1.4x 1.2x 1.9x 110 -> 61ms
set_x 1.5x 1.5x 1.3x 1.2x 1.9x 106 -> 59ms
set_y 1.4x 1.5x 1.3x 1.2x 1.9x 111 -> 60ms
set_z 1.4x 1.5x 1.4x 1.2x 1.9x 108 -> 60ms
shift 1.6x 1.5x 1.5x 1.1x 2.2x 94 -> 45ms
shift_onto_screen 1.9x 1.9x 1.6x 1.2x 1.6x 529 -> 332ms
stretch 1.3x 1.1x 1.1x 1.0x 1.0x 96 -> 95ms
stretch_about_point 1.2x 1.1x 1.2x 1.0x 1.0x 95 -> 93ms
stretch_to_fit_depth 1.1x 1.5x 3.8x 6.8x 5.8x 682 -> 119ms
stretch_to_fit_height 1.0x 1.5x 4.0x 6.7x 5.9x 667 -> 115ms
stretch_to_fit_width 1.1x 1.7x 3.9x 7.0x 5.8x 654 -> 113ms
surround 1.7x 1.8x 2.4x 3.3x 3.4x 1328 -> 398ms
to_corner 1.5x 1.5x 1.5x 1.2x 1.7x 123 -> 76ms
to_edge 1.6x 1.6x 1.4x 1.2x 1.7x 124 -> 76ms
width (get) 0.66x 1.9x 10.3x 32.9x 21.7x 546 -> 25ms
width (set) 1.5x 1.9x 3.1x 5.6x 5.3x 746 -> 144ms

To run the tests yourself, switch to the main branch and execute the following commands.

uv add pandas[output-formatting]
curl -o positionable.py "https://raw.githubusercontent.com/GniLudio/manim/refs/heads/rework-positioning/manim/mobject/abstract/positionable.py"
curl -o test.py "https://github.com/user-attachments/files/31893333/test.py"
python test.py

test.py

Future

Here are a few things that aren't addressed with this PR, but should definitely be discussed and/or changed in the future.

  • bounding box caching
  • calculating bounding box based on bezier curves
  • use Positionable for opengl

Links to added or changed documentation pages

Positionable.html, Mobject.html

Reviewer Checklist

  • The PR title is descriptive enough for the changelog, and the PR is labeled correctly
  • If applicable: newly added non-private functions and classes have a docstring including a short summary and a PARAMETERS section
  • If applicable: newly added functions and classes are tested

Comment on lines +367 to +374
def scale(
self,
# TODO: Rename to `factor`
scale_factor: float,
*,
about_point: Point3DLike | None = None,
about_edge: Vector3DLike | None = None,
) -> Self:
Comment on lines +1590 to +1591
# if self.has_no_points() and not mobject.submobjects:
# raise Warning("Attempting to replace mobject with no points")
Comment on lines +1600 to +1608
def surround(
self,
mobject: Positionable,
# TODO: Rename to `dim`
dim_to_match: int = 0,
stretch: bool = False,
*,
buff: float = MED_SMALL_BUFF,
) -> Self:
@GniLudio GniLudio added documentation Improvements or additions to documentation enhancement Additions and improvements in general refactor Refactor or redesign of existing code maintenance refactoring, typos, removing clutter/dead code, and other code quality improvements typehints For adding/discussing typehints performance labels Sep 6, 2026
@GniLudio

GniLudio commented Sep 7, 2026

Copy link
Copy Markdown
Contributor Author

The docs include the new class now: Positionable.html

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation enhancement Additions and improvements in general maintenance refactoring, typos, removing clutter/dead code, and other code quality improvements performance refactor Refactor or redesign of existing code typehints For adding/discussing typehints

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants