Skip to content

Commit

Permalink
Merge pull request #4 from 3b1b/master
Browse files Browse the repository at this point in the history
Sync
  • Loading branch information
xy-23 authored Apr 29, 2020
2 parents 8269a82 + af65c9d commit 18d5cd9
Show file tree
Hide file tree
Showing 3 changed files with 137 additions and 15 deletions.
8 changes: 4 additions & 4 deletions manimlib/camera/camera.py
Original file line number Diff line number Diff line change
Expand Up @@ -338,15 +338,15 @@ def set_cairo_context_path(self, ctx, vmobject):
return

ctx.new_path()
subpaths = vmobject.get_subpaths_from_points(points)
subpaths = vmobject.gen_subpaths_from_points_2d(points)
for subpath in subpaths:
quads = vmobject.get_cubic_bezier_tuples_from_points(subpath)
quads = vmobject.gen_cubic_bezier_tuples_from_points(subpath)
ctx.new_sub_path()
start = subpath[0]
ctx.move_to(*start[:2])
for p0, p1, p2, p3 in quads:
ctx.curve_to(*p1[:2], *p2[:2], *p3[:2])
if vmobject.consider_points_equals(subpath[0], subpath[-1]):
if vmobject.consider_points_equals_2d(subpath[0], subpath[-1]):
ctx.close_path()
return self

Expand Down Expand Up @@ -549,7 +549,7 @@ def adjust_out_of_range_points(self, points):
def transform_points_pre_display(self, mobject, points):
# Subclasses (like ThreeDCamera) may want to
# adjust points futher before they're shown
if np.any(np.isnan(points)) or np.any(points == np.inf):
if not np.all(np.isfinite(points)):
# TODO, print some kind of warning about
# mobject having invalid points?
points = np.zeros((1, 3))
Expand Down
56 changes: 45 additions & 11 deletions manimlib/mobject/types/vectorized_mobject.py
Original file line number Diff line number Diff line change
Expand Up @@ -595,35 +595,69 @@ def consider_points_equals(self, p0, p1):
atol=self.tolerance_for_point_equality
)

def consider_points_equals_2d(self, p0, p1):
"""
Determine if two points are close enough to be considered equal.
This uses the algorithm from np.isclose(), but expanded here for the
2D point case. NumPy is overkill for such a small question.
"""
rtol = 1.e-5 # default from np.isclose()
atol = self.tolerance_for_point_equality
if abs(p0[0] - p1[0]) > atol + rtol * abs(p1[0]):
return False
if abs(p0[1] - p1[1]) > atol + rtol * abs(p1[1]):
return False
return True

# Information about line
def get_cubic_bezier_tuples_from_points(self, points):
return np.array(list(self.gen_cubic_bezier_tuples_from_points(points)))

def gen_cubic_bezier_tuples_from_points(self, points):
"""
Get a generator for the cubic bezier tuples of this object.
Generator to not materialize a list or np.array needlessly.
"""
nppcc = VMobject.CONFIG["n_points_per_cubic_curve"]
remainder = len(points) % nppcc
points = points[:len(points) - remainder]
return np.array([
return (
points[i:i + nppcc]
for i in range(0, len(points), nppcc)
])
)

def get_cubic_bezier_tuples(self):
return self.get_cubic_bezier_tuples_from_points(
self.get_points()
)

def get_subpaths_from_points(self, points):
def _gen_subpaths_from_points(self, points, filter_func):
nppcc = self.n_points_per_cubic_curve
split_indices = filter(
lambda n: not self.consider_points_equals(
points[n - 1], points[n]
),
range(nppcc, len(points), nppcc)
)
split_indices = filter(filter_func, range(nppcc, len(points), nppcc))
split_indices = [0] + list(split_indices) + [len(points)]
return [
return (
points[i1:i2]
for i1, i2 in zip(split_indices, split_indices[1:])
if (i2 - i1) >= nppcc
]
)

def get_subpaths_from_points(self, points):
return list(
self._gen_subpaths_from_points(
points,
lambda n: not self.consider_points_equals(
points[n - 1], points[n]
))
)

def gen_subpaths_from_points_2d(self, points):
return self._gen_subpaths_from_points(
points,
lambda n: not self.consider_points_equals_2d(
points[n - 1], points[n]
))

def get_subpaths(self):
return self.get_subpaths_from_points(self.get_points())
Expand Down
88 changes: 88 additions & 0 deletions perf_scenes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
from manimlib.imports import *

"""
A set of scenes to be used for performance testing of Manim.
"""


class Perf1(GraphScene):
"""
A simple scene of two animations from the end of a video on recursion.
- Uses a graph in 1/4 of the scene.
- First fades in multiple lines of text and equations, and the graph axes.
- Next animates creation of two graphs and the creation of their text
labels.
"""
CONFIG = {
"x_axis_label":
"$n$",
"y_axis_label":
"$time$",
"x_axis_width":
FRAME_HEIGHT,
"y_axis_height":
FRAME_HEIGHT / 2,
"y_max":
50,
"y_min":
0,
"x_max":
100,
"x_min":
0,
"x_labeled_nums": [50, 100],
"y_labeled_nums":
range(0, 51, 10),
"y_tick_frequency":
10,
"x_tick_frequency":
10,
"axes_color":
BLUE,
"graph_origin":
np.array(
(-FRAME_X_RADIUS + LARGE_BUFF, -FRAME_Y_RADIUS + LARGE_BUFF, 0))
}

def construct(self):
t1 = TextMobject(
"Dividing a problem in half over and over means\\\\"
"the work done is proportional to $\\log_2{n}$").to_edge(UP)

t2 = TextMobject(
'\\textit{This is one of our\\\\favorite things to do in CS!}')
t2.to_edge(RIGHT)

t3 = TextMobject(
'The new \\texttt{power(x,n)} is \\underline{much}\\\\better than the old!'
)
t3.scale(0.8)
p1f = TexMobject('x^n=x \\times x^{n-1}').set_color(ORANGE)
t4 = TextMobject('\\textit{vs.}').scale(0.8)
p2f = TexMobject(
'x^n=x^{\\frac{n}{2}} \\times x^{\\frac{n}{2}}').set_color(GREEN)
p1v2g = VGroup(t3, p1f, t4, p2f).arrange(DOWN).center().to_edge(RIGHT)

self.setup_axes()
o_n = self.get_graph(lambda x: x, color=ORANGE, x_min=1, x_max=50)
o_log2n = self.get_graph(lambda x: math.log2(x),
color=GREEN,
x_min=2,
x_max=90)
onl = TexMobject('O(n)')
olog2nl = TexMobject('O(\\log_2{n})')
onl.next_to(o_n.get_point_from_function(0.6), UL)
olog2nl.next_to(o_log2n.get_point_from_function(0.8), UP)
self.play(
FadeIn(t1),
FadeIn(self.axes),
# FadeInFromDown(t2),
FadeIn(p1v2g),
)
self.play(ShowCreation(o_n),
ShowCreation(o_log2n),
ShowCreation(onl),
ShowCreation(olog2nl),
run_time=3)
self.wait(duration=5)

0 comments on commit 18d5cd9

Please sign in to comment.