Interpolation for vectorized mobjects implemented

This commit is contained in:
Grant Sanderson
2016-04-10 12:34:28 -07:00
parent 330b8870ba
commit 26c5aa8e67
12 changed files with 210 additions and 159 deletions

View File

@ -12,8 +12,7 @@ from mobject import Mobject, Point
class Transform(Animation): class Transform(Animation):
CONFIG = { CONFIG = {
"path_func" : straight_path, "path_func" : straight_path
"should_black_out_extra_points" : False
} }
def __init__(self, mobject, ending_mobject, **kwargs): def __init__(self, mobject, ending_mobject, **kwargs):
mobject = instantiate(mobject) mobject = instantiate(mobject)
@ -22,58 +21,24 @@ class Transform(Animation):
digest_config(self, kwargs, locals()) digest_config(self, kwargs, locals())
count1, count2 = mobject.get_num_points(), ending_mobject.get_num_points() count1, count2 = mobject.get_num_points(), ending_mobject.get_num_points()
if count2 == 0: if count2 == 0:
ending_mobject.add_points( ending_mobject = mobject.get_point_mobject()
[mobject.get_center()],
color = BLACK
)
count2 = ending_mobject.get_num_points() count2 = ending_mobject.get_num_points()
Mobject.align_data(mobject, ending_mobject) mobject.align_data(ending_mobject)
if self.should_black_out_extra_points and count2 < count1:
self.black_out_extra_points(count1, count2)
Animation.__init__(self, mobject, **kwargs) Animation.__init__(self, mobject, **kwargs)
self.name += "To" + str(ending_mobject) 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): def update_mobject(self, alpha):
families = map( families = map(
Mobject.submobject_family, Mobject.submobject_family,
[self.mobject, self.starting_mobject, self.ending_mobject] [self.mobject, self.starting_mobject, self.ending_mobject]
) )
for m, start, end in zip(*families): for m, start, end in zip(*families):
# print m, start, end m.interpolate(start, end, alpha, self.path_func)
m.points = self.path_func(
start.points, end.points, alpha
)
m.rgbs = straight_path(start.rgbs, end.rgbs, alpha)
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): class ClockwiseTransform(Transform):
CONFIG = { CONFIG = {
"path_func" : clockwise_path() "path_func" : clockwise_path()
@ -219,10 +184,10 @@ class TransformAnimations(Transform):
anim.set_run_time(self.run_time) anim.set_run_time(self.run_time)
if start_anim.starting_mobject.get_num_points() != end_anim.starting_mobject.get_num_points(): 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: for anim in start_anim, end_anim:
if hasattr(anim, "ending_mobject"): 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) Transform.__init__(self, start_anim.mobject, end_anim.mobject, **kwargs)
#Rewire starting and ending mobjects #Rewire starting and ending mobjects

View File

@ -71,19 +71,18 @@ class Camera(object):
mob.nonempty_family_members() mob.nonempty_family_members()
for mob in mobjects for mob in mobjects
]) ])
vect_mobjects = []
for mobject in mobjects: for mobject in mobjects:
if isinstance(mobject, VectorizedMobject): if isinstance(mobject, VectorizedMobject):
vect_mobjects.append(mobject) self.display_vectorized(mobject)
elif isinstance(mobject, PointCloudMobject): elif isinstance(mobject, PointCloudMobject):
self.display_point_cloud( self.display_point_cloud(
mobject.points, mobject.rgbs, mobject.points, mobject.rgbs,
self.adjusted_thickness(mobject.point_thickness) self.adjusted_thickness(mobject.stroke_width)
) )
else: else:
raise Exception("I don't know how to display that") #TODO
if vect_mobjects: print mobject
self.display_vectorized(vect_mobjects) # raise Exception("I don't know how to display that")
# def display_region(self, region): # def display_region(self, region):
# (h, w) = self.pixel_shape # (h, w) = self.pixel_shape
@ -98,25 +97,23 @@ class Camera(object):
# self.pixel_array[covered] = rgb # 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") im = Image.fromarray(self.pixel_array, mode = "RGB")
canvas = aggdraw.Draw(im) canvas = aggdraw.Draw(im)
for mob in vect_mobjects: pen, fill = self.get_pen_and_fill(vect_mobject)
pen, fill = self.get_pen_and_fill(mob)
#TODO, fill
pathstring = self.get_pathstring( pathstring = self.get_pathstring(
self.points_to_pixel_coords(mob.points), self.points_to_pixel_coords(vect_mobject.points),
closed = mob.is_closed() closed = vect_mobject.is_closed()
) )
symbol = aggdraw.Symbol(pathstring) symbol = aggdraw.Symbol(pathstring)
canvas.symbol((0, 0), symbol, pen, fill) canvas.symbol((0, 0), symbol, pen, fill)
canvas.flush() canvas.flush()
self.pixel_array = np.array(im) self.pixel_array[:,:] = np.array(im)
def get_pen_and_fill(self, vect_mobject): def get_pen_and_fill(self, vect_mobject):
pen = aggdraw.Pen( pen = aggdraw.Pen(
vect_mobject.get_color().get_web(), vect_mobject.get_stroke_color().get_web(),
vect_mobject.point_thickness vect_mobject.stroke_width
) )
fill = aggdraw.Brush( fill = aggdraw.Brush(
vect_mobject.get_fill_color().get_web(), vect_mobject.get_fill_color().get_web(),
@ -124,8 +121,6 @@ class Camera(object):
) )
return (pen, fill) return (pen, fill)
def get_pathstring(self, cubic_bezier_points, closed = False): def get_pathstring(self, cubic_bezier_points, closed = False):
start = "m%d,%d"%tuple(cubic_bezier_points[0]) start = "m%d,%d"%tuple(cubic_bezier_points[0])
#(handle1, handle2, anchor) tripletes #(handle1, handle2, anchor) tripletes

View File

@ -25,6 +25,23 @@ def compass_directions(n = 4, start_vect = UP):
for k in range(n) 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): def bezier(points):
n = len(points) - 1 n = len(points) - 1
return lambda t : sum([ return lambda t : sum([

View File

@ -15,7 +15,7 @@ class ImageMobject(Mobject):
"filter_color" : "black", "filter_color" : "black",
"invert" : True, "invert" : True,
"use_cache" : True, "use_cache" : True,
"point_thickness" : 1, "stroke_width" : 1,
"scale_value" : 1.0, "scale_value" : 1.0,
"should_center" : True, "should_center" : True,
} }

View File

@ -18,7 +18,7 @@ class Mobject(object):
#Number of numbers used to describe a point (3 for pos, 3 for normal vector) #Number of numbers used to describe a point (3 for pos, 3 for normal vector)
CONFIG = { CONFIG = {
"color" : WHITE, "color" : WHITE,
"point_thickness" : DEFAULT_POINT_THICKNESS, "stroke_width" : DEFAULT_POINT_THICKNESS,
"name" : None, "name" : None,
"display_mode" : "points", #TODO, REMOVE "display_mode" : "points", #TODO, REMOVE
"dim" : 3, "dim" : 3,
@ -109,7 +109,7 @@ class Mobject(object):
def rotate(self, angle, axis = OUT, axes = []): def rotate(self, angle, axis = OUT, axes = []):
if len(axes) == 0: if len(axes) == 0:
axes = [axis] axes = [axis]
rot_matrix = np.identity(self.DIM) rot_matrix = np.identity(self.dim)
for axis in axes: for axis in axes:
rot_matrix = np.dot(rot_matrix, rotation_matrix(angle, axis)) rot_matrix = np.dot(rot_matrix, rotation_matrix(angle, axis))
t_rot_matrix = np.transpose(rot_matrix) t_rot_matrix = np.transpose(rot_matrix)
@ -135,7 +135,7 @@ class Mobject(object):
alphas = alphas**wag_factor alphas = alphas**wag_factor
mob.points += np.dot( mob.points += np.dot(
alphas.reshape((len(alphas), 1)), alphas.reshape((len(alphas), 1)),
np.array(direction).reshape((1, mob.DIM)) np.array(direction).reshape((1, mob.dim))
) )
return self return self
@ -310,7 +310,7 @@ class Mobject(object):
return 0 return 0
def get_merged_array(self, array_attr): 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(): for mob in self.nonempty_family_members():
result = np.append(result, getattr(mob, array_attr), 0) result = np.append(result, getattr(mob, array_attr), 0)
return result return result
@ -327,7 +327,7 @@ class Mobject(object):
return len(self.points) return len(self.points)
def get_critical_point(self, direction): def get_critical_point(self, direction):
result = np.zeros(self.DIM) result = np.zeros(self.dim)
for dim in [0, 1]: for dim in [0, 1]:
if direction[dim] <= 0: if direction[dim] <= 0:
min_point = self.reduce_across_dimension(np.min, np.min, dim) min_point = self.reduce_across_dimension(np.min, np.min, dim)
@ -350,7 +350,7 @@ class Mobject(object):
return self.get_critical_point(direction) return self.get_critical_point(direction)
def get_center(self): 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): def get_center_of_mass(self):
return np.apply_along_axis(np.mean, 0, self.get_all_points()) return np.apply_along_axis(np.mean, 0, self.get_all_points())
@ -405,51 +405,51 @@ class Mobject(object):
) )
## Alignment ## Alignment
def align_data(self, mobject):
@staticmethod self.align_points(mobject)
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)
)
#Recurse #Recurse
diff = len(mobject1.sub_mobjects) - len(mobject2.sub_mobjects) diff = len(self.sub_mobjects) - len(mobject.sub_mobjects)
if diff < 0:
larger, smaller = mobject2, mobject1
elif diff > 0:
larger, smaller = mobject1, mobject2
if diff != 0: 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):]: for sub_mob in larger.sub_mobjects[-abs(diff):]:
smaller.add(Point(sub_mob.get_center())) smaller.add(sub_mob.get_point_mobject())
for m1, m2 in zip(mobject1.sub_mobjects, mobject2.sub_mobjects): for m1, m2 in zip(self.sub_mobjects, mobject.sub_mobjects):
Mobject.align_data(m1, m2) 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 Turns target_mobject into an interpolation between mobject1
and mobject2. and mobject2.
""" """
#TODO self.points = path_func(
Mobject.align_data(mobject1, mobject2) mobject1.points, mobject2.points, alpha
for attr in self.get_array_attrs(): )
setattr(self, attr, interpolate( self.interpolate_color(mobject1, mobject2, alpha)
getattr(mobject1, attr),
getattr(mobject2, attr), def interpolate_color(self, mobject1, mobject2, alpha):
alpha)) raise Exception("Not implemented")

View File

@ -110,6 +110,23 @@ class PointCloudMobject(Mobject):
index = alpha*(self.get_num_points()-1) index = alpha*(self.get_num_points()-1)
return self.points[index] 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 #TODO, Make the two implementations bellow non-redundant
class Mobject1D(PointCloudMobject): class Mobject1D(PointCloudMobject):
@ -146,13 +163,11 @@ class Mobject2D(PointCloudMobject):
class Point(Mobject): class Point(PointCloudMobject):
CONFIG = { CONFIG = {
"color" : BLACK, "color" : BLACK,
} }
def __init__(self, location = ORIGIN, **kwargs): def __init__(self, location = ORIGIN, **kwargs):
digest_locals(self) PointCloudMobject.__init__(self, **kwargs)
Mobject.__init__(self, **kwargs) self.add_points([location])
def generate_points(self):
self.add_points([self.location])

View File

@ -8,7 +8,7 @@ class TexMobject(Mobject):
CONFIG = { CONFIG = {
"template_tex_file" : TEMPLATE_TEX_FILE, "template_tex_file" : TEMPLATE_TEX_FILE,
"color" : WHITE, "color" : WHITE,
"point_thickness" : 1, "stroke_width" : 1,
"should_center" : True, "should_center" : True,
} }
def __init__(self, expression, **kwargs): def __init__(self, expression, **kwargs):

View File

@ -35,7 +35,7 @@ class VectorizedMobject(Mobject):
def get_fill_opacity(self): def get_fill_opacity(self):
return self.fill_opacity return self.fill_opacity
def get_storke_color(self): def get_stroke_color(self):
return Color(rgb = self.stroke_rgb) return Color(rgb = self.stroke_rgb)
#TODO, get color? Specify if stroke or fill #TODO, get color? Specify if stroke or fill
@ -88,18 +88,18 @@ class VectorizedMobject(Mobject):
] ]
def set_points_as_corners(self, points): def set_points_as_corners(self, points):
if len(points) <= 1:
return self
points = self.close_if_needed(points)
handles1 = points[:-1] handles1 = points[:-1]
handles2 = points[1:] handles2 = points[1:]
self.set_anchors_and_handles(points, handles1, handles2) self.set_anchors_and_handles(points, handles1, handles2)
return self return self
def set_points_smoothly(self, points): def set_points_smoothly(self, points):
if self.is_closed(): if len(points) <= 1:
points = np.append( return self
points, points = self.close_if_needed(points)
[points[0], points[1]],
axis = 0
)
num_handles = len(points) - 1 num_handles = len(points) - 1
#Must solve 2*num_handles equations to get the handles. #Must solve 2*num_handles equations to get the handles.
#l and u are the number of lower an upper diagonal rows #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[1,1::2] = 1
diag[2,1:-2:2] = -2 diag[2,1:-2:2] = -2
diag[3,0:-3:2] = 1 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, #This is the b as in Ax = b, where we are solving for x,
#and A is represented using diag. However, think of entries #and A is represented using diag. However, think of entries
#to x and b as being points in space, not numbers #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[1::2] = 2*points[1:]
b[0] = points[0] b[0] = points[0]
b[-1] = points[-1] 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)) handle_pairs = np.zeros((2*num_handles, self.dim))
for i in range(self.dim): for i in range(self.dim):
handle_pairs[:,i] = linalg.solve_banded( handle_pairs[:,i] = solve_func(b[:,i])
(l, u), diag, b[:,i]
)
handles1 = handle_pairs[0::2] handles1 = handle_pairs[0::2]
handles2 = handle_pairs[1::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) 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"): def set_points(self, points, mode = "smooth"):
points = np.array(points) points = np.array(points)
@ -157,17 +170,63 @@ class VectorizedMobject(Mobject):
## Information about line ## Information about line
def get_num_points(self): def get_num_points(self):
pass return (len(self.points) - 1)/3 + 1
def point_from_proportion(self, alpha): 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])

View File

@ -14,7 +14,7 @@ from scene import Scene
from topics.complex_numbers import * from topics.complex_numbers import *
DEFAULT_PLANE_CONFIG = { DEFAULT_PLANE_CONFIG = {
"point_thickness" : 2*DEFAULT_POINT_THICKNESS "stroke_width" : 2*DEFAULT_POINT_THICKNESS
class SuccessiveComplexMultiplications(ComplexMultiplication): class SuccessiveComplexMultiplications(ComplexMultiplication):
@ -144,7 +144,7 @@ class DrawSolutionsToZToTheNEqualsW(Scene):
plane = ComplexPlane(**plane_config) plane = ComplexPlane(**plane_config)
circle = Circle( circle = Circle(
radius = radius*zoom_value, radius = radius*zoom_value,
point_thickness = plane.point_thickness stroke_width = plane.stroke_width
) )
solutions = [ solutions = [
radius*np.exp(complex(0, 1)*(2*np.pi*k + theta)/n) radius*np.exp(complex(0, 1)*(2*np.pi*k + theta)/n)
@ -222,7 +222,7 @@ class DrawComplexAngleAndMagnitude(Scene):
Line( Line(
start, end, start, end,
color = color, color = color,
point_thickness = self.plane.point_thickness stroke_width = self.plane.stroke_width
) )
for start, end, color in zip( for start, end, color in zip(
[ORIGIN, point[0]*RIGHT, ORIGIN], [ORIGIN, point[0]*RIGHT, ORIGIN],

View File

@ -10,7 +10,7 @@ from helpers import *
from scene import Scene from scene import Scene
from number_line import NumberLineScene 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 LIGHT_RED = RED_E
def matrix_to_string(matrix): def matrix_to_string(matrix):
@ -55,7 +55,7 @@ class ShowMultiplication(NumberLineScene):
def construct(self, num, show_original_line): def construct(self, num, show_original_line):
config = { config = {
"density" : max(abs(num), 1)*DEFAULT_POINT_DENSITY_1D, "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: if abs(num) < 1:
config["numerical_radius"] = SPACE_WIDTH/num config["numerical_radius"] = SPACE_WIDTH/num
@ -114,7 +114,7 @@ class ExamplesOfNonlinearOneDimensionalTransforms(NumberLineScene):
self.clear() self.clear()
self.add(self.nonlinear) self.add(self.nonlinear)
config = { config = {
"point_thickness" : 2*DEFAULT_POINT_THICKNESS, "stroke_width" : 2*DEFAULT_POINT_THICKNESS,
"density" : 5*DEFAULT_POINT_DENSITY_1D, "density" : 5*DEFAULT_POINT_DENSITY_1D,
} }
NumberLineScene.construct(self, **config) NumberLineScene.construct(self, **config)
@ -143,7 +143,7 @@ class ShowTwoThenThree(ShowMultiplication):
def construct(self): def construct(self):
config = { config = {
"point_thickness" : 2*DEFAULT_POINT_THICKNESS, "stroke_width" : 2*DEFAULT_POINT_THICKNESS,
"density" : 6*DEFAULT_POINT_DENSITY_1D, "density" : 6*DEFAULT_POINT_DENSITY_1D,
} }
NumberLineScene.construct(self, **config) NumberLineScene.construct(self, **config)
@ -162,7 +162,7 @@ class TransformScene2D(Scene):
"x_radius" : 2*SPACE_WIDTH, "x_radius" : 2*SPACE_WIDTH,
"y_radius" : 2*SPACE_WIDTH, "y_radius" : 2*SPACE_WIDTH,
"density" : DEFAULT_POINT_DENSITY_1D*density_factor, "density" : DEFAULT_POINT_DENSITY_1D*density_factor,
"point_thickness" : 2*DEFAULT_POINT_THICKNESS "stroke_width" : 2*DEFAULT_POINT_THICKNESS
} }
if not use_faded_lines: if not use_faded_lines:
config["x_faded_line_frequency"] = None config["x_faded_line_frequency"] = None
@ -318,7 +318,7 @@ class ExamplesOfNonlinearTwoDimensionalTransformations(Scene):
"x_radius" : 2*SPACE_WIDTH, "x_radius" : 2*SPACE_WIDTH,
"y_radius" : 2*SPACE_WIDTH, "y_radius" : 2*SPACE_WIDTH,
"density" : 3*DEFAULT_POINT_DENSITY_1D, "density" : 3*DEFAULT_POINT_DENSITY_1D,
"point_thickness" : 2*DEFAULT_POINT_THICKNESS "stroke_width" : 2*DEFAULT_POINT_THICKNESS
} }
number_plane = NumberPlane(**config) number_plane = NumberPlane(**config)
numbers = number_plane.get_coordinate_labels() numbers = number_plane.get_coordinate_labels()
@ -372,7 +372,7 @@ class TrickyExamplesOfNonlinearTwoDimensionalTransformations(Scene):
"x_radius" : 1.2*SPACE_WIDTH, "x_radius" : 1.2*SPACE_WIDTH,
"y_radius" : 1.2*SPACE_WIDTH, "y_radius" : 1.2*SPACE_WIDTH,
"density" : 10*DEFAULT_POINT_DENSITY_1D, "density" : 10*DEFAULT_POINT_DENSITY_1D,
"point_thickness" : 2*DEFAULT_POINT_THICKNESS "stroke_width" : 2*DEFAULT_POINT_THICKNESS
} }
number_plane = NumberPlane(**config) number_plane = NumberPlane(**config)
phrase1, phrase2 = TextMobject([ phrase1, phrase2 = TextMobject([

View File

@ -95,7 +95,7 @@ class OpenInterval(Mobject):
class Piano(ImageMobject): class Piano(ImageMobject):
CONFIG = { CONFIG = {
"point_thickness" : 1, "stroke_width" : 1,
"invert" : False, "invert" : False,
"scale_value" : 0.5 "scale_value" : 0.5
} }
@ -113,7 +113,7 @@ class Piano(ImageMobject):
for count in range(14): for count in range(14):
key = Mobject( key = Mobject(
color = "white", color = "white",
point_thickness = 1 stroke_width = 1
) )
x0 = left + count*self.ivory_jump x0 = left + count*self.ivory_jump
x1 = x0 + self.ivory_jump x1 = x0 + self.ivory_jump
@ -664,7 +664,7 @@ class ConstructPiano(Scene):
askew = deepcopy(keys[-1]) askew = deepcopy(keys[-1])
keys[-1].rotate_in_place(np.pi/5) keys[-1].rotate_in_place(np.pi/5)
for key in keys: for key in keys:
key.point_thickness = 1 key.stroke_width = 1
key_copy = deepcopy(key).to_corner(DOWN+LEFT) key_copy = deepcopy(key).to_corner(DOWN+LEFT)
key_copy.scale_in_place(0.25) key_copy.scale_in_place(0.25)
key_copy.shift(1.8*random.random()*SPACE_WIDTH*RIGHT) key_copy.shift(1.8*random.random()*SPACE_WIDTH*RIGHT)

View File

@ -8,7 +8,7 @@ from helpers import *
class Stars(Mobject): class Stars(Mobject):
CONFIG = { CONFIG = {
"point_thickness" : 1, "stroke_width" : 1,
"radius" : SPACE_WIDTH, "radius" : SPACE_WIDTH,
"num_points" : 1000, "num_points" : 1000,
} }