mirror of
https://github.com/ManimCommunity/manim.git
synced 2026-06-22 10:01:47 +00:00
Implemented :meth:.MovingCamera.auto_zoom for automatically zooming onto specified mobjects (#2162)
* feature request #1056 Added auto_zoom to moving_camera. Fixed is_in_frame. * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Fixed indentation * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Removed faulty comment Keeps failing automated test so i removed it. * Update manim/camera/moving_camera.py padding vs. margin :-) Co-authored-by: Benjamin Hackl <devel@benjamin-hackl.at> * Update manim/camera/moving_camera.py Co-authored-by: Benjamin Hackl <devel@benjamin-hackl.at> * Update manim/camera/moving_camera.py Co-authored-by: Benjamin Hackl <devel@benjamin-hackl.at> * Update manim/camera/moving_camera.py Co-authored-by: Benjamin Hackl <devel@benjamin-hackl.at> * Update manim/camera/moving_camera.py Co-authored-by: Benjamin Hackl <devel@benjamin-hackl.at> * Tidied the code snake_casing > camelCasing :-) or > | and > & * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Update manim/camera/moving_camera.py Co-authored-by: Benjamin Hackl <devel@benjamin-hackl.at> * Update tests/test_auto_zoom.py Co-authored-by: Benjamin Hackl <devel@benjamin-hackl.at> * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Update manim/camera/moving_camera.py Co-authored-by: Benjamin Hackl <devel@benjamin-hackl.at> * fixed snake_casing and removed unused imports * Update manim/camera/moving_camera.py Co-authored-by: Benjamin Hackl <devel@benjamin-hackl.at> * remove above comment * Update tests/test_auto_zoom.py * Update tests/test_auto_zoom.py Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Darylgolden <darylgolden@gmail.com> Co-authored-by: Benjamin Hackl <devel@benjamin-hackl.at>
This commit is contained in:
parent
3a8b8625c7
commit
59d4ea9888
3 changed files with 101 additions and 6 deletions
|
|
@ -454,10 +454,10 @@ class Camera:
|
|||
return not reduce(
|
||||
op.or_,
|
||||
[
|
||||
mobject.get_right()[0] < fc[0] - fw,
|
||||
mobject.get_bottom()[1] > fc[1] + fh,
|
||||
mobject.get_left()[0] > fc[0] + fw,
|
||||
mobject.get_top()[1] < fc[1] - fh,
|
||||
mobject.get_right()[0] < fc[0] - fw / 2,
|
||||
mobject.get_bottom()[1] > fc[1] + fh / 2,
|
||||
mobject.get_left()[0] > fc[0] + fw / 2,
|
||||
mobject.get_top()[1] < fc[1] - fh / 2,
|
||||
],
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -8,10 +8,9 @@
|
|||
|
||||
__all__ = ["CameraFrame", "MovingCamera"]
|
||||
|
||||
|
||||
from .. import config
|
||||
from ..camera.camera import Camera
|
||||
from ..constants import ORIGIN
|
||||
from ..constants import DOWN, LEFT, ORIGIN, RIGHT, UP
|
||||
from ..mobject.frame import ScreenRectangle
|
||||
from ..mobject.types.vectorized_mobject import VGroup
|
||||
from ..utils.color import WHITE
|
||||
|
|
@ -173,3 +172,76 @@ class MovingCamera(Camera):
|
|||
list
|
||||
"""
|
||||
return [self.frame]
|
||||
|
||||
def auto_zoom(self, mobjects, margin=0, only_mobjects_in_frame=False):
|
||||
"""Zooms on to a given array of mobjects (or a singular mobject)
|
||||
and automatically resizes to frame all the mobjects.
|
||||
|
||||
.. NOTE::
|
||||
|
||||
This method only works when 2D-objects in the XY-plane are considered, it
|
||||
will not work correctly when the camera has been rotated.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
mobjects
|
||||
The mobject or array of mobjects that the camera will focus on.
|
||||
|
||||
margin
|
||||
The width of the margin that is added to the frame (optional, 0 by default).
|
||||
|
||||
only_mobjects_in_frame
|
||||
If set to ``True``, only allows focusing on mobjects that are already in frame.
|
||||
|
||||
Returns
|
||||
-------
|
||||
_AnimationBuilder
|
||||
Returns an animation that zooms the camera view to a given
|
||||
list of mobjects.
|
||||
|
||||
"""
|
||||
scene_critical_x_left = None
|
||||
scene_critical_x_right = None
|
||||
scene_critical_y_up = None
|
||||
scene_critical_y_down = None
|
||||
|
||||
for m in mobjects:
|
||||
if (m == self.frame) or (
|
||||
only_mobjects_in_frame and not self.is_in_frame(m)
|
||||
):
|
||||
# detected camera frame, should not be used to calculate final position of camera
|
||||
continue
|
||||
|
||||
# initialize scene critical points with first mobjects critical points
|
||||
if scene_critical_x_left == None:
|
||||
scene_critical_x_left = m.get_critical_point(LEFT)[0]
|
||||
scene_critical_x_right = m.get_critical_point(RIGHT)[0]
|
||||
scene_critical_y_up = m.get_critical_point(UP)[1]
|
||||
scene_critical_y_down = m.get_critical_point(DOWN)[1]
|
||||
|
||||
else:
|
||||
if m.get_critical_point(LEFT)[0] < scene_critical_x_left:
|
||||
scene_critical_x_left = m.get_critical_point(LEFT)[0]
|
||||
|
||||
if m.get_critical_point(RIGHT)[0] > scene_critical_x_right:
|
||||
scene_critical_x_right = m.get_critical_point(RIGHT)[0]
|
||||
|
||||
if m.get_critical_point(UP)[1] > scene_critical_y_up:
|
||||
scene_critical_y_up = m.get_critical_point(UP)[1]
|
||||
|
||||
if m.get_critical_point(DOWN)[1] < scene_critical_y_down:
|
||||
scene_critical_y_down = m.get_critical_point(DOWN)[1]
|
||||
|
||||
# calculate center x and y
|
||||
x = (scene_critical_x_left + scene_critical_x_right) / 2
|
||||
y = (scene_critical_y_up + scene_critical_y_down) / 2
|
||||
|
||||
# calculate proposed width and height of zoomed scene
|
||||
new_width = abs(scene_critical_x_left - scene_critical_x_right)
|
||||
new_height = abs(scene_critical_y_up - scene_critical_y_down)
|
||||
|
||||
# zoom to fit all mobjects along the side that has the largest size
|
||||
if new_width / self.frame.width > new_height / self.frame.height:
|
||||
return self.frame.animate.set_x(x).set_y(y).set(width=new_width + margin)
|
||||
else:
|
||||
return self.frame.animate.set_x(x).set_y(y).set(height=new_height + margin)
|
||||
|
|
|
|||
23
tests/test_auto_zoom.py
Normal file
23
tests/test_auto_zoom.py
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
from manim import *
|
||||
|
||||
|
||||
def test_zoom():
|
||||
|
||||
s1 = Square()
|
||||
s1.set_x(-10)
|
||||
s2 = Square()
|
||||
s2.set_x(10)
|
||||
|
||||
with tempconfig({"dry_run": True, "quality": "low_quality"}):
|
||||
scene = MovingCameraScene()
|
||||
scene.add(s1, s2)
|
||||
scene.play(scene.camera.auto_zoom([s1, s2]))
|
||||
|
||||
assert (
|
||||
scene.camera.frame_width
|
||||
== abs(
|
||||
s1.get_left()[0] - s2.get_right()[0],
|
||||
)
|
||||
and scene.camera.frame.get_center()[0]
|
||||
== (abs(s1.get_center()[0] + s2.get_center()[0]) / 2)
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue