mirror of
https://github.com/3b1b/manim.git
synced 2025-07-29 13:03:31 +08:00
Interpolation for vectorized mobjects implemented
This commit is contained in:
@ -12,8 +12,7 @@ from mobject import Mobject, Point
|
||||
|
||||
class Transform(Animation):
|
||||
CONFIG = {
|
||||
"path_func" : straight_path,
|
||||
"should_black_out_extra_points" : False
|
||||
"path_func" : straight_path
|
||||
}
|
||||
def __init__(self, mobject, ending_mobject, **kwargs):
|
||||
mobject = instantiate(mobject)
|
||||
@ -22,58 +21,24 @@ class Transform(Animation):
|
||||
digest_config(self, kwargs, locals())
|
||||
count1, count2 = mobject.get_num_points(), ending_mobject.get_num_points()
|
||||
if count2 == 0:
|
||||
ending_mobject.add_points(
|
||||
[mobject.get_center()],
|
||||
color = BLACK
|
||||
)
|
||||
ending_mobject = mobject.get_point_mobject()
|
||||
count2 = ending_mobject.get_num_points()
|
||||
Mobject.align_data(mobject, ending_mobject)
|
||||
if self.should_black_out_extra_points and count2 < count1:
|
||||
self.black_out_extra_points(count1, count2)
|
||||
mobject.align_data(ending_mobject)
|
||||
|
||||
Animation.__init__(self, mobject, **kwargs)
|
||||
self.name += "To" + str(ending_mobject)
|
||||
self.mobject.point_thickness = ending_mobject.point_thickness
|
||||
self.mobject.stroke_width = ending_mobject.stroke_width
|
||||
|
||||
|
||||
def black_out_extra_points(self, count1, count2):
|
||||
#Ensure redundant pixels fade to black
|
||||
indices = np.arange(
|
||||
0, count1-1, float(count1) / count2
|
||||
).astype('int')
|
||||
temp = np.zeros(self.ending_mobject.points.shape)
|
||||
temp[indices] = self.ending_mobject.rgbs[indices]
|
||||
self.ending_mobject.rgbs = temp
|
||||
self.non_redundant_m2_indices = indices
|
||||
|
||||
def update_mobject(self, alpha):
|
||||
families = map(
|
||||
Mobject.submobject_family,
|
||||
[self.mobject, self.starting_mobject, self.ending_mobject]
|
||||
)
|
||||
for m, start, end in zip(*families):
|
||||
# print m, start, end
|
||||
m.points = self.path_func(
|
||||
start.points, end.points, alpha
|
||||
)
|
||||
m.rgbs = straight_path(start.rgbs, end.rgbs, alpha)
|
||||
m.interpolate(start, end, alpha, self.path_func)
|
||||
|
||||
|
||||
def clean_up(self):
|
||||
Animation.clean_up(self)
|
||||
if hasattr(self, "non_redundant_m2_indices"):
|
||||
#Reduce mobject (which has become identical to mobject2), as
|
||||
#well as mobject2 itself
|
||||
for mobject in [self.mobject, self.ending_mobject]:
|
||||
for attr in ['points', 'rgbs']:
|
||||
setattr(
|
||||
mobject, attr,
|
||||
getattr(
|
||||
self.ending_mobject,
|
||||
attr
|
||||
)[self.non_redundant_m2_indices]
|
||||
)
|
||||
|
||||
class ClockwiseTransform(Transform):
|
||||
CONFIG = {
|
||||
"path_func" : clockwise_path()
|
||||
@ -219,10 +184,10 @@ class TransformAnimations(Transform):
|
||||
anim.set_run_time(self.run_time)
|
||||
|
||||
if start_anim.starting_mobject.get_num_points() != end_anim.starting_mobject.get_num_points():
|
||||
Mobject.align_data(start_anim.starting_mobject, end_anim.starting_mobject)
|
||||
start_anim.starting_mobject.align_data(end_anim.starting_mobject)
|
||||
for anim in start_anim, end_anim:
|
||||
if hasattr(anim, "ending_mobject"):
|
||||
Mobject.align_data(anim.starting_mobject, anim.ending_mobject)
|
||||
anim.starting_mobject.align_data(anim.ending_mobject)
|
||||
|
||||
Transform.__init__(self, start_anim.mobject, end_anim.mobject, **kwargs)
|
||||
#Rewire starting and ending mobjects
|
||||
|
29
camera.py
29
camera.py
@ -71,19 +71,18 @@ class Camera(object):
|
||||
mob.nonempty_family_members()
|
||||
for mob in mobjects
|
||||
])
|
||||
vect_mobjects = []
|
||||
for mobject in mobjects:
|
||||
if isinstance(mobject, VectorizedMobject):
|
||||
vect_mobjects.append(mobject)
|
||||
self.display_vectorized(mobject)
|
||||
elif isinstance(mobject, PointCloudMobject):
|
||||
self.display_point_cloud(
|
||||
mobject.points, mobject.rgbs,
|
||||
self.adjusted_thickness(mobject.point_thickness)
|
||||
self.adjusted_thickness(mobject.stroke_width)
|
||||
)
|
||||
else:
|
||||
raise Exception("I don't know how to display that")
|
||||
if vect_mobjects:
|
||||
self.display_vectorized(vect_mobjects)
|
||||
#TODO
|
||||
print mobject
|
||||
# raise Exception("I don't know how to display that")
|
||||
|
||||
# def display_region(self, region):
|
||||
# (h, w) = self.pixel_shape
|
||||
@ -98,25 +97,23 @@ class Camera(object):
|
||||
# self.pixel_array[covered] = rgb
|
||||
|
||||
|
||||
def display_vectorized(self, vect_mobjects):
|
||||
def display_vectorized(self, vect_mobject):
|
||||
im = Image.fromarray(self.pixel_array, mode = "RGB")
|
||||
canvas = aggdraw.Draw(im)
|
||||
for mob in vect_mobjects:
|
||||
pen, fill = self.get_pen_and_fill(mob)
|
||||
#TODO, fill
|
||||
pen, fill = self.get_pen_and_fill(vect_mobject)
|
||||
pathstring = self.get_pathstring(
|
||||
self.points_to_pixel_coords(mob.points),
|
||||
closed = mob.is_closed()
|
||||
self.points_to_pixel_coords(vect_mobject.points),
|
||||
closed = vect_mobject.is_closed()
|
||||
)
|
||||
symbol = aggdraw.Symbol(pathstring)
|
||||
canvas.symbol((0, 0), symbol, pen, fill)
|
||||
canvas.flush()
|
||||
self.pixel_array = np.array(im)
|
||||
self.pixel_array[:,:] = np.array(im)
|
||||
|
||||
def get_pen_and_fill(self, vect_mobject):
|
||||
pen = aggdraw.Pen(
|
||||
vect_mobject.get_color().get_web(),
|
||||
vect_mobject.point_thickness
|
||||
vect_mobject.get_stroke_color().get_web(),
|
||||
vect_mobject.stroke_width
|
||||
)
|
||||
fill = aggdraw.Brush(
|
||||
vect_mobject.get_fill_color().get_web(),
|
||||
@ -124,8 +121,6 @@ class Camera(object):
|
||||
)
|
||||
return (pen, fill)
|
||||
|
||||
|
||||
|
||||
def get_pathstring(self, cubic_bezier_points, closed = False):
|
||||
start = "m%d,%d"%tuple(cubic_bezier_points[0])
|
||||
#(handle1, handle2, anchor) tripletes
|
||||
|
17
helpers.py
17
helpers.py
@ -25,6 +25,23 @@ def compass_directions(n = 4, start_vect = UP):
|
||||
for k in range(n)
|
||||
]
|
||||
|
||||
def diag_to_matrix(l_and_u, diag):
|
||||
"""
|
||||
Converts array whose rows represent diagonal
|
||||
entries of a matrix into the matrix itself.
|
||||
See scipy.linalg.solve_banded
|
||||
"""
|
||||
l, u = l_and_u
|
||||
dim = diag.shape[1]
|
||||
matrix = np.zeros((dim, dim))
|
||||
for i in range(l+u+1):
|
||||
np.fill_diagonal(
|
||||
matrix[max(0,i-u):,max(0,u-i):],
|
||||
diag[i,max(0,u-i):]
|
||||
)
|
||||
return matrix
|
||||
|
||||
|
||||
def bezier(points):
|
||||
n = len(points) - 1
|
||||
return lambda t : sum([
|
||||
|
@ -15,7 +15,7 @@ class ImageMobject(Mobject):
|
||||
"filter_color" : "black",
|
||||
"invert" : True,
|
||||
"use_cache" : True,
|
||||
"point_thickness" : 1,
|
||||
"stroke_width" : 1,
|
||||
"scale_value" : 1.0,
|
||||
"should_center" : True,
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ class Mobject(object):
|
||||
#Number of numbers used to describe a point (3 for pos, 3 for normal vector)
|
||||
CONFIG = {
|
||||
"color" : WHITE,
|
||||
"point_thickness" : DEFAULT_POINT_THICKNESS,
|
||||
"stroke_width" : DEFAULT_POINT_THICKNESS,
|
||||
"name" : None,
|
||||
"display_mode" : "points", #TODO, REMOVE
|
||||
"dim" : 3,
|
||||
@ -109,7 +109,7 @@ class Mobject(object):
|
||||
def rotate(self, angle, axis = OUT, axes = []):
|
||||
if len(axes) == 0:
|
||||
axes = [axis]
|
||||
rot_matrix = np.identity(self.DIM)
|
||||
rot_matrix = np.identity(self.dim)
|
||||
for axis in axes:
|
||||
rot_matrix = np.dot(rot_matrix, rotation_matrix(angle, axis))
|
||||
t_rot_matrix = np.transpose(rot_matrix)
|
||||
@ -135,7 +135,7 @@ class Mobject(object):
|
||||
alphas = alphas**wag_factor
|
||||
mob.points += np.dot(
|
||||
alphas.reshape((len(alphas), 1)),
|
||||
np.array(direction).reshape((1, mob.DIM))
|
||||
np.array(direction).reshape((1, mob.dim))
|
||||
)
|
||||
return self
|
||||
|
||||
@ -310,7 +310,7 @@ class Mobject(object):
|
||||
return 0
|
||||
|
||||
def get_merged_array(self, array_attr):
|
||||
result = np.zeros((0, self.DIM))
|
||||
result = np.zeros((0, self.dim))
|
||||
for mob in self.nonempty_family_members():
|
||||
result = np.append(result, getattr(mob, array_attr), 0)
|
||||
return result
|
||||
@ -327,7 +327,7 @@ class Mobject(object):
|
||||
return len(self.points)
|
||||
|
||||
def get_critical_point(self, direction):
|
||||
result = np.zeros(self.DIM)
|
||||
result = np.zeros(self.dim)
|
||||
for dim in [0, 1]:
|
||||
if direction[dim] <= 0:
|
||||
min_point = self.reduce_across_dimension(np.min, np.min, dim)
|
||||
@ -350,7 +350,7 @@ class Mobject(object):
|
||||
return self.get_critical_point(direction)
|
||||
|
||||
def get_center(self):
|
||||
return self.get_critical_point(np.zeros(self.DIM))
|
||||
return self.get_critical_point(np.zeros(self.dim))
|
||||
|
||||
def get_center_of_mass(self):
|
||||
return np.apply_along_axis(np.mean, 0, self.get_all_points())
|
||||
@ -405,51 +405,51 @@ class Mobject(object):
|
||||
)
|
||||
|
||||
## Alignment
|
||||
|
||||
@staticmethod
|
||||
def align_data(mobject1, mobject2):
|
||||
count1 = len(mobject1.points)
|
||||
count2 = len(mobject2.points)
|
||||
if count1 != count2:
|
||||
if count1 < count2:
|
||||
smaller = mobject1
|
||||
target_size = count2
|
||||
else:
|
||||
smaller = mobject2
|
||||
target_size = count1
|
||||
if len(smaller.points) == 0:
|
||||
smaller.add_points(
|
||||
[np.zeros(smaller.DIM)],
|
||||
color = BLACK
|
||||
)
|
||||
smaller.apply_over_attr_arrays(
|
||||
lambda a : streth_array_to_length(a, target_size)
|
||||
)
|
||||
def align_data(self, mobject):
|
||||
self.align_points(mobject)
|
||||
#Recurse
|
||||
diff = len(mobject1.sub_mobjects) - len(mobject2.sub_mobjects)
|
||||
|
||||
if diff < 0:
|
||||
larger, smaller = mobject2, mobject1
|
||||
elif diff > 0:
|
||||
larger, smaller = mobject1, mobject2
|
||||
diff = len(self.sub_mobjects) - len(mobject.sub_mobjects)
|
||||
if diff != 0:
|
||||
if diff < 0:
|
||||
larger, smaller = mobject, self
|
||||
elif diff > 0:
|
||||
larger, smaller = self, mobject
|
||||
for sub_mob in larger.sub_mobjects[-abs(diff):]:
|
||||
smaller.add(Point(sub_mob.get_center()))
|
||||
for m1, m2 in zip(mobject1.sub_mobjects, mobject2.sub_mobjects):
|
||||
Mobject.align_data(m1, m2)
|
||||
smaller.add(sub_mob.get_point_mobject())
|
||||
for m1, m2 in zip(self.sub_mobjects, mobject.sub_mobjects):
|
||||
m1.align_data(m2)
|
||||
|
||||
def interpolate(self, mobject1, mobject2, alpha):
|
||||
def get_point_mobject(self):
|
||||
"""
|
||||
The simplest mobject to be transformed to or from self.
|
||||
Should by a point of the appropriate type
|
||||
"""
|
||||
raise Exception("Not implemented")
|
||||
|
||||
def align_points(self, mobject):
|
||||
count1 = self.get_num_points()
|
||||
count2 = mobject.get_num_points()
|
||||
if count1 < count2:
|
||||
self.align_points_with_larger(mobject)
|
||||
elif count2 < count1:
|
||||
mobject.align_points_with_larger(self)
|
||||
return self
|
||||
|
||||
def align_points_with_larger(self, larger_mobject):
|
||||
raise Exception("Not implemented")
|
||||
|
||||
def interpolate(self, mobject1, mobject2, alpha, path_func):
|
||||
"""
|
||||
Turns target_mobject into an interpolation between mobject1
|
||||
and mobject2.
|
||||
"""
|
||||
#TODO
|
||||
Mobject.align_data(mobject1, mobject2)
|
||||
for attr in self.get_array_attrs():
|
||||
setattr(self, attr, interpolate(
|
||||
getattr(mobject1, attr),
|
||||
getattr(mobject2, attr),
|
||||
alpha))
|
||||
self.points = path_func(
|
||||
mobject1.points, mobject2.points, alpha
|
||||
)
|
||||
self.interpolate_color(mobject1, mobject2, alpha)
|
||||
|
||||
def interpolate_color(self, mobject1, mobject2, alpha):
|
||||
raise Exception("Not implemented")
|
||||
|
||||
|
||||
|
||||
|
@ -110,6 +110,23 @@ class PointCloudMobject(Mobject):
|
||||
index = alpha*(self.get_num_points()-1)
|
||||
return self.points[index]
|
||||
|
||||
# Alignment
|
||||
def align_points_with_larger(self, larger_mobject):
|
||||
assert(isinstance(larger_mobject, PointCloudMobject))
|
||||
self.apply_over_attr_arrays(
|
||||
lambda a : streth_array_to_length(
|
||||
a, larger_mobject.get_num_points()
|
||||
)
|
||||
)
|
||||
|
||||
def get_point_mobject(self):
|
||||
return Point(self.get_center())
|
||||
|
||||
def interpolate_color(self, mobject1, mobject2, alpha):
|
||||
self.rgbs = interpolate(
|
||||
mobject1.rgbs, mobject2.rgbs, alpha
|
||||
)
|
||||
|
||||
|
||||
#TODO, Make the two implementations bellow non-redundant
|
||||
class Mobject1D(PointCloudMobject):
|
||||
@ -146,13 +163,11 @@ class Mobject2D(PointCloudMobject):
|
||||
|
||||
|
||||
|
||||
class Point(Mobject):
|
||||
class Point(PointCloudMobject):
|
||||
CONFIG = {
|
||||
"color" : BLACK,
|
||||
}
|
||||
def __init__(self, location = ORIGIN, **kwargs):
|
||||
digest_locals(self)
|
||||
Mobject.__init__(self, **kwargs)
|
||||
PointCloudMobject.__init__(self, **kwargs)
|
||||
self.add_points([location])
|
||||
|
||||
def generate_points(self):
|
||||
self.add_points([self.location])
|
||||
|
@ -8,7 +8,7 @@ class TexMobject(Mobject):
|
||||
CONFIG = {
|
||||
"template_tex_file" : TEMPLATE_TEX_FILE,
|
||||
"color" : WHITE,
|
||||
"point_thickness" : 1,
|
||||
"stroke_width" : 1,
|
||||
"should_center" : True,
|
||||
}
|
||||
def __init__(self, expression, **kwargs):
|
||||
|
@ -35,7 +35,7 @@ class VectorizedMobject(Mobject):
|
||||
def get_fill_opacity(self):
|
||||
return self.fill_opacity
|
||||
|
||||
def get_storke_color(self):
|
||||
def get_stroke_color(self):
|
||||
return Color(rgb = self.stroke_rgb)
|
||||
|
||||
#TODO, get color? Specify if stroke or fill
|
||||
@ -88,18 +88,18 @@ class VectorizedMobject(Mobject):
|
||||
]
|
||||
|
||||
def set_points_as_corners(self, points):
|
||||
if len(points) <= 1:
|
||||
return self
|
||||
points = self.close_if_needed(points)
|
||||
handles1 = points[:-1]
|
||||
handles2 = points[1:]
|
||||
self.set_anchors_and_handles(points, handles1, handles2)
|
||||
return self
|
||||
|
||||
def set_points_smoothly(self, points):
|
||||
if self.is_closed():
|
||||
points = np.append(
|
||||
points,
|
||||
[points[0], points[1]],
|
||||
axis = 0
|
||||
)
|
||||
if len(points) <= 1:
|
||||
return self
|
||||
points = self.close_if_needed(points)
|
||||
num_handles = len(points) - 1
|
||||
#Must solve 2*num_handles equations to get the handles.
|
||||
#l and u are the number of lower an upper diagonal rows
|
||||
@ -115,6 +115,8 @@ class VectorizedMobject(Mobject):
|
||||
diag[1,1::2] = 1
|
||||
diag[2,1:-2:2] = -2
|
||||
diag[3,0:-3:2] = 1
|
||||
diag[2,-2] = 1
|
||||
diag[1,-1] = -2
|
||||
#This is the b as in Ax = b, where we are solving for x,
|
||||
#and A is represented using diag. However, think of entries
|
||||
#to x and b as being points in space, not numbers
|
||||
@ -122,25 +124,36 @@ class VectorizedMobject(Mobject):
|
||||
b[1::2] = 2*points[1:]
|
||||
b[0] = points[0]
|
||||
b[-1] = points[-1]
|
||||
|
||||
solve_func = lambda b : linalg.solve_banded(
|
||||
(l, u), diag, b
|
||||
)
|
||||
if self.is_closed():
|
||||
#Get equations to relate first and last points
|
||||
matrix = diag_to_matrix((l, u), diag)
|
||||
#last row handles second derivative
|
||||
matrix[-1, [0, 1]] = matrix[0, [0, 1]]
|
||||
#first row handles first derivative
|
||||
matrix[0,:] = np.zeros(matrix.shape[1])
|
||||
matrix[0,[0, -1]] = [1, 1]
|
||||
b[0] = 2*points[0]
|
||||
b[-1] = np.zeros(self.dim)
|
||||
solve_func = lambda b : linalg.solve(matrix, b)
|
||||
handle_pairs = np.zeros((2*num_handles, self.dim))
|
||||
for i in range(self.dim):
|
||||
handle_pairs[:,i] = linalg.solve_banded(
|
||||
(l, u), diag, b[:,i]
|
||||
)
|
||||
handle_pairs[:,i] = solve_func(b[:,i])
|
||||
handles1 = handle_pairs[0::2]
|
||||
handles2 = handle_pairs[1::2]
|
||||
if self.is_closed():
|
||||
#Ignore last point that was artificially added
|
||||
#to smooth out the closing.
|
||||
#TODO, is the the best say to handle this?
|
||||
handles1[0] = handles1[-1]
|
||||
points = points[:-1]
|
||||
handles1 = handles1[:-1]
|
||||
handles2 = handles2[:-1]
|
||||
|
||||
self.set_anchors_and_handles(points, handles1, handles2)
|
||||
return self
|
||||
|
||||
def close_if_needed(self, points):
|
||||
if self.is_closed() and not np.all(points[0] == points[-1]):
|
||||
points = np.append(
|
||||
points,
|
||||
[points[0]],
|
||||
axis = 0
|
||||
)
|
||||
return points
|
||||
|
||||
def set_points(self, points, mode = "smooth"):
|
||||
points = np.array(points)
|
||||
@ -157,17 +170,63 @@ class VectorizedMobject(Mobject):
|
||||
## Information about line
|
||||
|
||||
def get_num_points(self):
|
||||
pass
|
||||
return (len(self.points) - 1)/3 + 1
|
||||
|
||||
def point_from_proportion(self, alpha):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
num_cubics = self.get_num_points()-1
|
||||
interpoint_alpha = num_cubics*(alpha % (1./num_cubics))
|
||||
index = 3*int(alpha*num_cubics)
|
||||
cubic = bezier(self.points[index:index+4])
|
||||
return cubic(interpoint_alpha)
|
||||
|
||||
|
||||
## Alignment
|
||||
def align_points_with_larger(self, larger_mobject):
|
||||
assert(isinstance(larger_mobject, VectorizedMobject))
|
||||
anchors, handles1, handles2 = self.get_anchors_and_handles()
|
||||
old_n = len(anchors)
|
||||
new_n = larger_mobject.get_num_points()
|
||||
#Buff up list of anchor points to appropriate length
|
||||
new_anchors = anchors[old_n*np.arange(new_n)/new_n]
|
||||
#At first, handles are on anchor points
|
||||
#the [2:] is because start has no handles
|
||||
new_points = new_anchors.repeat(3, axis = 0)[2:]
|
||||
#These indices indicate the spots between genuinely
|
||||
#different anchor points in new_points list
|
||||
indices = 3*(np.arange(old_n) * new_n / old_n)[1:]
|
||||
new_points[indices+1] = handles1
|
||||
new_points[indices+2] = handles2
|
||||
self.set_points(new_points, mode = "handles_included")
|
||||
return self
|
||||
|
||||
|
||||
def get_point_mobject(self):
|
||||
return VectorizedPoint(self.get_center())
|
||||
|
||||
def interpolate_color(self, mobject1, mobject2, alpha):
|
||||
attrs = [
|
||||
"stroke_rgb",
|
||||
"stroke_width",
|
||||
"fill_rgb",
|
||||
"fill_opacity",
|
||||
]
|
||||
for attr in attrs:
|
||||
setattr(self, attr, interpolate(
|
||||
getattr(mobject1, attr),
|
||||
getattr(mobject2, attr),
|
||||
alpha
|
||||
))
|
||||
|
||||
|
||||
|
||||
|
||||
class VectorizedPoint(VectorizedMobject):
|
||||
CONFIG = {
|
||||
"color" : BLACK,
|
||||
}
|
||||
def __init__(self, location = ORIGIN, **kwargs):
|
||||
VectorizedMobject.__init__(self, **kwargs)
|
||||
self.set_points([location])
|
||||
|
||||
|
||||
|
||||
|
@ -14,7 +14,7 @@ from scene import Scene
|
||||
from topics.complex_numbers import *
|
||||
|
||||
DEFAULT_PLANE_CONFIG = {
|
||||
"point_thickness" : 2*DEFAULT_POINT_THICKNESS
|
||||
"stroke_width" : 2*DEFAULT_POINT_THICKNESS
|
||||
|
||||
|
||||
class SuccessiveComplexMultiplications(ComplexMultiplication):
|
||||
@ -144,7 +144,7 @@ class DrawSolutionsToZToTheNEqualsW(Scene):
|
||||
plane = ComplexPlane(**plane_config)
|
||||
circle = Circle(
|
||||
radius = radius*zoom_value,
|
||||
point_thickness = plane.point_thickness
|
||||
stroke_width = plane.stroke_width
|
||||
)
|
||||
solutions = [
|
||||
radius*np.exp(complex(0, 1)*(2*np.pi*k + theta)/n)
|
||||
@ -222,7 +222,7 @@ class DrawComplexAngleAndMagnitude(Scene):
|
||||
Line(
|
||||
start, end,
|
||||
color = color,
|
||||
point_thickness = self.plane.point_thickness
|
||||
stroke_width = self.plane.stroke_width
|
||||
)
|
||||
for start, end, color in zip(
|
||||
[ORIGIN, point[0]*RIGHT, ORIGIN],
|
||||
|
@ -10,7 +10,7 @@ from helpers import *
|
||||
from scene import Scene
|
||||
from number_line import NumberLineScene
|
||||
|
||||
ARROW_CONFIG = {"point_thickness" : 2*DEFAULT_POINT_THICKNESS}
|
||||
ARROW_CONFIG = {"stroke_width" : 2*DEFAULT_POINT_THICKNESS}
|
||||
LIGHT_RED = RED_E
|
||||
|
||||
def matrix_to_string(matrix):
|
||||
@ -55,7 +55,7 @@ class ShowMultiplication(NumberLineScene):
|
||||
def construct(self, num, show_original_line):
|
||||
config = {
|
||||
"density" : max(abs(num), 1)*DEFAULT_POINT_DENSITY_1D,
|
||||
"point_thickness" : 2*DEFAULT_POINT_THICKNESS
|
||||
"stroke_width" : 2*DEFAULT_POINT_THICKNESS
|
||||
}
|
||||
if abs(num) < 1:
|
||||
config["numerical_radius"] = SPACE_WIDTH/num
|
||||
@ -114,7 +114,7 @@ class ExamplesOfNonlinearOneDimensionalTransforms(NumberLineScene):
|
||||
self.clear()
|
||||
self.add(self.nonlinear)
|
||||
config = {
|
||||
"point_thickness" : 2*DEFAULT_POINT_THICKNESS,
|
||||
"stroke_width" : 2*DEFAULT_POINT_THICKNESS,
|
||||
"density" : 5*DEFAULT_POINT_DENSITY_1D,
|
||||
}
|
||||
NumberLineScene.construct(self, **config)
|
||||
@ -143,7 +143,7 @@ class ShowTwoThenThree(ShowMultiplication):
|
||||
|
||||
def construct(self):
|
||||
config = {
|
||||
"point_thickness" : 2*DEFAULT_POINT_THICKNESS,
|
||||
"stroke_width" : 2*DEFAULT_POINT_THICKNESS,
|
||||
"density" : 6*DEFAULT_POINT_DENSITY_1D,
|
||||
}
|
||||
NumberLineScene.construct(self, **config)
|
||||
@ -162,7 +162,7 @@ class TransformScene2D(Scene):
|
||||
"x_radius" : 2*SPACE_WIDTH,
|
||||
"y_radius" : 2*SPACE_WIDTH,
|
||||
"density" : DEFAULT_POINT_DENSITY_1D*density_factor,
|
||||
"point_thickness" : 2*DEFAULT_POINT_THICKNESS
|
||||
"stroke_width" : 2*DEFAULT_POINT_THICKNESS
|
||||
}
|
||||
if not use_faded_lines:
|
||||
config["x_faded_line_frequency"] = None
|
||||
@ -318,7 +318,7 @@ class ExamplesOfNonlinearTwoDimensionalTransformations(Scene):
|
||||
"x_radius" : 2*SPACE_WIDTH,
|
||||
"y_radius" : 2*SPACE_WIDTH,
|
||||
"density" : 3*DEFAULT_POINT_DENSITY_1D,
|
||||
"point_thickness" : 2*DEFAULT_POINT_THICKNESS
|
||||
"stroke_width" : 2*DEFAULT_POINT_THICKNESS
|
||||
}
|
||||
number_plane = NumberPlane(**config)
|
||||
numbers = number_plane.get_coordinate_labels()
|
||||
@ -372,7 +372,7 @@ class TrickyExamplesOfNonlinearTwoDimensionalTransformations(Scene):
|
||||
"x_radius" : 1.2*SPACE_WIDTH,
|
||||
"y_radius" : 1.2*SPACE_WIDTH,
|
||||
"density" : 10*DEFAULT_POINT_DENSITY_1D,
|
||||
"point_thickness" : 2*DEFAULT_POINT_THICKNESS
|
||||
"stroke_width" : 2*DEFAULT_POINT_THICKNESS
|
||||
}
|
||||
number_plane = NumberPlane(**config)
|
||||
phrase1, phrase2 = TextMobject([
|
||||
|
@ -95,7 +95,7 @@ class OpenInterval(Mobject):
|
||||
|
||||
class Piano(ImageMobject):
|
||||
CONFIG = {
|
||||
"point_thickness" : 1,
|
||||
"stroke_width" : 1,
|
||||
"invert" : False,
|
||||
"scale_value" : 0.5
|
||||
}
|
||||
@ -113,7 +113,7 @@ class Piano(ImageMobject):
|
||||
for count in range(14):
|
||||
key = Mobject(
|
||||
color = "white",
|
||||
point_thickness = 1
|
||||
stroke_width = 1
|
||||
)
|
||||
x0 = left + count*self.ivory_jump
|
||||
x1 = x0 + self.ivory_jump
|
||||
@ -664,7 +664,7 @@ class ConstructPiano(Scene):
|
||||
askew = deepcopy(keys[-1])
|
||||
keys[-1].rotate_in_place(np.pi/5)
|
||||
for key in keys:
|
||||
key.point_thickness = 1
|
||||
key.stroke_width = 1
|
||||
key_copy = deepcopy(key).to_corner(DOWN+LEFT)
|
||||
key_copy.scale_in_place(0.25)
|
||||
key_copy.shift(1.8*random.random()*SPACE_WIDTH*RIGHT)
|
||||
|
@ -8,7 +8,7 @@ from helpers import *
|
||||
|
||||
class Stars(Mobject):
|
||||
CONFIG = {
|
||||
"point_thickness" : 1,
|
||||
"stroke_width" : 1,
|
||||
"radius" : SPACE_WIDTH,
|
||||
"num_points" : 1000,
|
||||
}
|
||||
|
Reference in New Issue
Block a user