def update_group(group, alpha): area, left_v_line, left_T_label, right_v_line, right_T_label = group t_min = interpolate(curr_t_min, new_t_min, alpha) t_max = interpolate(curr_t_max, new_t_max, alpha) new_area = self.get_area(graph, t_min, t_max) new_left_v_line = self.get_vertical_line_to_graph( t_min, graph ) new_left_v_line.set_color(left_v_line.get_color()) left_T_label.move_to(new_left_v_line.get_bottom(), UP) new_right_v_line = self.get_vertical_line_to_graph( t_max, graph ) new_right_v_line.set_color(right_v_line.get_color()) right_T_label.move_to(new_right_v_line.get_bottom(), UP) # Fade close to 0 if fade_close_to_origin: if len(left_T_label) > 0: left_T_label[0].set_fill(opacity=min(1, np.abs(t_min))) if len(right_T_label) > 0: right_T_label[0].set_fill(opacity=min(1, np.abs(t_max))) Transform(area, new_area).update(1) Transform(left_v_line, new_left_v_line).update(1) Transform(right_v_line, new_right_v_line).update(1) return group
def update_func(group, alpha): dx = interpolate(start_dx, target_dx, alpha) x = interpolate(start_x, target_x, alpha) kwargs = dict(secant_slope_group.kwargs) kwargs["dx"] = dx kwargs["x"] = x new_group = self.get_secant_slope_group(**kwargs) group.become(new_group) return group
def add_line_to(self, point): nppcc = self.n_points_per_cubic_curve self.add_cubic_bezier_curve_to(*[ interpolate(self.get_last_point(), point, a) for a in np.linspace(0, 1, nppcc)[1:] ]) return self
def compile_play_args_to_animation_list(self, *args, **kwargs): """ Add animations so that all pi creatures look at the first mobject being animated with each .play call """ animations = Scene.compile_play_args_to_animation_list(self, *args, **kwargs) if not self.any_pi_creatures_on_screen(): return animations pi_creatures = self.get_on_screen_pi_creatures() non_pi_creature_anims = [ anim for anim in animations if len(set(anim.mobject.get_family()).intersection(pi_creatures)) == 0 ] if len(non_pi_creature_anims) == 0: return animations # Get pi creatures to look at whatever # is being animated first_anim = non_pi_creature_anims[0] main_mobject = first_anim.mobject animations += [ UpdateFromAlphaFunc( pi_creature, lambda p, a: p.look_at( interpolate( p.get_look_at_spot(), main_mobject.get_center(), a, ) ), ) for pi_creature in pi_creatures ] return animations
def __init__(self, decimal_mob, target_number, **kwargs): start_number = decimal_mob.number super().__init__( decimal_mob, lambda a: interpolate(start_number, target_number, a), **kwargs )
def random_bright_color(): color = random_color() curr_rgb = color_to_rgb(color) new_rgb = interpolate( curr_rgb, np.ones(len(curr_rgb)), 0.5 ) return Color(rgb=new_rgb)
def straight_path(start_points, end_points, alpha): """ Same function as interpolate, but renamed to reflect intent of being used to determine how a set of points move to another set. For instance, it should be a specific case of path_along_arc """ return interpolate(start_points, end_points, alpha)
def set_points_as_corners(self, points): nppcc = self.n_points_per_cubic_curve points = np.array(points) self.set_anchors_and_handles(*[ interpolate(points[:-1], points[1:], a) for a in np.linspace(0, 1, nppcc) ]) return self
def set_colors_by_radial_gradient(self, center=None, radius=1, inner_color=WHITE, outer_color=BLACK): start_rgba, end_rgba = list(map(color_to_rgba, [start_color, end_color])) if center is None: center = self.get_center() for mob in self.family_members_with_points(): num_points = mob.get_num_points() t = min(1, np.abs(mob.get_center() - center) / radius) mob.rgbas = np.array( [interpolate(start_rgba, end_rgba, t)] * num_points ) return self
def add_line(self, start, end, color=None): start, end = list(map(np.array, [start, end])) length = get_norm(end - start) if length == 0: points = [start] else: epsilon = self.epsilon / length points = [ interpolate(start, end, t) for t in np.arange(0, 1, epsilon) ] self.add_points(points, color=color)
def point_to_number(self, point): start_point, end_point = self.get_start_and_end() full_vect = end_point - start_point unit_vect = normalize(full_vect) def distance_from_start(p): return np.dot(p - start_point, unit_vect) proportion = fdiv( distance_from_start(point), distance_from_start(end_point) ) return interpolate(self.x_min, self.x_max, proportion)
def func(values): alphas = inverse_interpolate( min_value, max_value, np.array(values) ) alphas = np.clip(alphas, 0, 1) # if flip_alphas: # alphas = 1 - alphas scaled_alphas = alphas * (len(rgbs) - 1) indices = scaled_alphas.astype(int) next_indices = np.clip(indices + 1, 0, len(rgbs) - 1) inter_alphas = scaled_alphas % 1 inter_alphas = inter_alphas.repeat(3).reshape((len(indices), 3)) result = interpolate(rgbs[indices], rgbs[next_indices], inter_alphas) return result
def color_gradient(reference_colors, length_of_output): if length_of_output == 0: return reference_colors[0] rgbs = list(map(color_to_rgb, reference_colors)) alphas = np.linspace(0, (len(rgbs) - 1), length_of_output) floors = alphas.astype('int') alphas_mod1 = alphas % 1 # End edge case alphas_mod1[-1] = 1 floors[-1] = len(rgbs) - 2 return [ rgb_to_color(interpolate(rgbs[i], rgbs[i + 1], alpha)) for i, alpha in zip(floors, alphas_mod1) ]
def change_anchor_mode(self, mode): assert(mode in ["jagged", "smooth"]) nppcc = self.n_points_per_cubic_curve for submob in self.family_members_with_points(): subpaths = submob.get_subpaths() submob.clear_points() for subpath in subpaths: anchors = np.append( subpath[::nppcc], subpath[-1:], 0 ) if mode == "smooth": h1, h2 = get_smooth_handle_points(anchors) elif mode == "jagged": a1 = anchors[:-1] a2 = anchors[1:] h1 = interpolate(a1, a2, 1.0 / 3) h2 = interpolate(a1, a2, 2.0 / 3) new_subpath = np.array(subpath) new_subpath[1::nppcc] = h1 new_subpath[2::nppcc] = h2 submob.append_points(new_subpath) return self
def set_color_by_gradient(self, *colors): self.rgbas = np.array(list(map( color_to_rgba, color_gradient(colors, len(self.points)) ))) return self start_rgba, end_rgba = list(map(color_to_rgba, [start_color, end_color])) for mob in self.family_members_with_points(): num_points = mob.get_num_points() mob.rgbas = np.array([ interpolate(start_rgba, end_rgba, alpha) for alpha in np.arange(num_points) / float(num_points) ]) return self
def get_number_design(self, value, symbol): num = int(value) n_rows = { 2: 2, 3: 3, 4: 2, 5: 2, 6: 3, 7: 3, 8: 3, 9: 4, 10: 4, }[num] n_cols = 1 if num in [2, 3] else 2 insertion_indices = { 5: [0], 7: [0], 8: [0, 1], 9: [1], 10: [0, 2], }.get(num, []) top = self.get_top() + symbol.get_height() * DOWN bottom = self.get_bottom() + symbol.get_height() * UP column_points = [ interpolate(top, bottom, alpha) for alpha in np.linspace(0, 1, n_rows) ] design = VGroup(*[ symbol.copy().move_to(point) for point in column_points ]) if n_cols == 2: space = 0.2 * self.get_width() column_copy = design.copy().shift(space * RIGHT) design.shift(space * LEFT) design.add(*column_copy) design.add(*[ symbol.copy().move_to( center_of_mass(column_points[i:i + 2]) ) for i in insertion_indices ]) for symbol in design: if symbol.get_center()[1] < self.get_center()[1]: symbol.rotate_in_place(np.pi) return design
def interpolate_color(self, mobject1, mobject2, alpha): attrs = [ "fill_rgbas", "stroke_rgbas", "background_stroke_rgbas", "stroke_width", "background_stroke_width", "sheen_direction", "sheen_factor", ] for attr in attrs: setattr(self, attr, interpolate( getattr(mobject1, attr), getattr(mobject2, attr), alpha )) if alpha == 1.0: setattr(self, attr, getattr(mobject2, attr))
def get_number_design(self, value, symbol): num = int(value) n_rows = { 2: 2, 3: 3, 4: 2, 5: 2, 6: 3, 7: 3, 8: 3, 9: 4, 10: 4, }[num] n_cols = 1 if num in [2, 3] else 2 insertion_indices = { 5: [0], 7: [0], 8: [0, 1], 9: [1], 10: [0, 2], }.get(num, []) top = self.get_top() + symbol.get_height() * DOWN bottom = self.get_bottom() + symbol.get_height() * UP column_points = [ interpolate(top, bottom, alpha) for alpha in np.linspace(0, 1, n_rows) ] design = VGroup( *[symbol.copy().move_to(point) for point in column_points]) if n_cols == 2: space = 0.2 * self.get_width() column_copy = design.copy().shift(space * RIGHT) design.shift(space * LEFT) design.add(*column_copy) design.add(*[ symbol.copy().move_to(center_of_mass(column_points[i:i + 2])) for i in insertion_indices ]) for symbol in design: if symbol.get_center()[1] < self.get_center()[1]: symbol.rotate_in_place(np.pi) return design
def change_anchor_mode(self, mode): assert (mode in ["jagged", "smooth"]) nppc = self.n_points_per_curve for submob in self.family_members_with_points(): subpaths = submob.get_subpaths() submob.clear_points() for subpath in subpaths: anchors = np.vstack([subpath[::nppc], subpath[-1:]]) if mode == "smooth": h1, h2 = get_smooth_handle_points(anchors) new_subpath = get_quadratic_approximation_of_cubic( anchors[:-1], h1, h2, anchors[1:]) elif mode == "jagged": new_subpath = np.array(subpath) new_subpath[1::nppc] = interpolate(anchors[:-1], anchors[1:], 0.5) submob.append_points(new_subpath) submob.refresh_triangulation() return self
def generate_points(self): length = get_norm(self.end - self.start) if length == 0: self.add(Line(self.start, self.end)) return self num_interp_points = int(length / self.dashed_segment_length) # Even number ensures that start and end points are hit if num_interp_points % 2 == 1: num_interp_points += 1 points = [ interpolate(self.start, self.end, alpha) for alpha in np.linspace(0, 1, num_interp_points) ] includes = it.cycle([True, False]) self.submobjects = [ Line(p1, p2, **self.init_kwargs) for p1, p2, include in zip(points, points[1:], includes) if include ] self.put_start_and_end_on_with_projection(self.start, self.end) return self
def generate_points(self): dim, border = self.get_dimension_and_border() axis = self.get_rotation_axis() anchors = border.get_anchors() num_pts = dim + 1 lpts, rpts = pts = [[ interpolate(sv, ev, alpha) for alpha in np.linspace(0, 1, num_pts) ][1:-1] for sv, ev in (anchors[0:2:1], anchors[-2:-4:-1])] lines = VGroup(*[ DashedLine(lp, rp, **self.line_config) for lp, rp in zip(lpts, rpts) ]) for angle in np.linspace(0, 2 * np.pi, 6, endpoint=False): self.add(lines.copy().rotate_about_origin(angle, axis=axis)) for k in range(3): self.add(DashedLine(anchors[k], anchors[k + 3], **self.line_config)) # Hacky solution to the perspective problem in 3D if self.mob_type == "ct": height = self.ct_or_hexagon.get_height() self.shift(height * (IN + LEFT + DOWN))
def interpolate_submobject(self, submobject, starting_sumobject, alpha): anchor_widths = self.submob_to_anchor_widths[hash(submobject)] # Create a gaussian such that 3 sigmas out on either side # will equals time_width tw = self.time_width sigma = tw / 6 mu = interpolate(-tw / 2, 1 + tw / 2, alpha) def gauss_kernel(x): if abs(x - mu) > 3 * sigma: return 0 z = (x - mu) / sigma return math.exp(-0.5 * z * z) kernel_array = list( map(gauss_kernel, np.linspace(0, 1, len(anchor_widths)))) scaled_widths = anchor_widths * kernel_array new_widths = np.zeros(submobject.get_num_points()) new_widths[0::3] = scaled_widths[:-1] new_widths[2::3] = scaled_widths[1:] new_widths[1::3] = (new_widths[0::3] + new_widths[2::3]) / 2 submobject.set_stroke(width=new_widths)
def fractalification_iteration(vmobject, dimension=1.05, num_inserted_anchors_range=list(range(1, 4))): num_points = vmobject.get_num_points() if num_points > 0: # original_anchors = vmobject.get_anchors() original_anchors = [ vmobject.point_from_proportion(x) for x in np.linspace(0, 1 - 1. / num_points, num_points) ] new_anchors = [] for p1, p2, in zip(original_anchors, original_anchors[1:]): num_inserts = random.choice(num_inserted_anchors_range) inserted_points = [ interpolate(p1, p2, alpha) for alpha in np.linspace(0, 1, num_inserts + 2)[1:-1] ] mass_scaling_factor = 1. / (num_inserts + 1) length_scaling_factor = mass_scaling_factor**(1. / dimension) target_length = get_norm(p1 - p2) * length_scaling_factor curr_length = get_norm(p1 - p2) * mass_scaling_factor # offset^2 + curr_length^2 = target_length^2 offset_len = np.sqrt(target_length**2 - curr_length**2) unit_vect = (p1 - p2) / get_norm(p1 - p2) offset_unit_vect = rotate_vector(unit_vect, np.pi / 2) inserted_points = [ point + u * offset_len * offset_unit_vect for u, point in zip(it.cycle([-1, 1]), inserted_points) ] new_anchors += [p1] + inserted_points new_anchors.append(original_anchors[-1]) vmobject.set_points_as_corners(new_anchors) vmobject.set_submobjects([ fractalification_iteration(submob, dimension, num_inserted_anchors_range) for submob in vmobject.submobjects ]) return vmobject
def update_submobject(self, submobject, starting_submobject, alpha): submobject.pointwise_become_partial(starting_submobject, 0, min(2 * alpha, 1)) if alpha < 0.5: if self.stroke_color: color = self.stroke_color elif starting_submobject.stroke_width > 0: color = starting_submobject.get_stroke_color() else: color = starting_submobject.get_color() submobject.set_stroke(color, width=self.stroke_width) submobject.set_fill(opacity=0) else: if not self.reached_halfway_point_before: self.reached_halfway_point_before = True submobject.points = np.array(starting_submobject.points) width, opacity = [ interpolate(start, end, 2 * alpha - 1) for start, end in [(self.stroke_width, starting_submobject.get_stroke_width()), (0, starting_submobject.get_fill_opacity())] ] submobject.set_stroke(width=width) submobject.set_fill(opacity=opacity)
def fractalification_iteration(vmobject, dimension=1.05, num_inserted_anchors_range=list(range(1, 4))): num_points = vmobject.get_num_points() if num_points > 0: # original_anchors = vmobject.get_anchors() original_anchors = [ vmobject.point_from_proportion(x) for x in np.linspace(0, 1 - 1. / num_points, num_points) ] new_anchors = [] for p1, p2, in zip(original_anchors, original_anchors[1:]): num_inserts = random.choice(num_inserted_anchors_range) inserted_points = [ interpolate(p1, p2, alpha) for alpha in np.linspace(0, 1, num_inserts + 2)[1:-1] ] mass_scaling_factor = 1. / (num_inserts + 1) length_scaling_factor = mass_scaling_factor**(1. / dimension) target_length = get_norm(p1 - p2) * length_scaling_factor curr_length = get_norm(p1 - p2) * mass_scaling_factor # offset^2 + curr_length^2 = target_length^2 offset_len = np.sqrt(target_length**2 - curr_length**2) unit_vect = (p1 - p2) / get_norm(p1 - p2) offset_unit_vect = rotate_vector(unit_vect, np.pi / 2) inserted_points = [ point + u * offset_len * offset_unit_vect for u, point in zip(it.cycle([-1, 1]), inserted_points) ] new_anchors += [p1] + inserted_points new_anchors.append(original_anchors[-1]) vmobject.set_points_as_corners(new_anchors) vmobject.submobjects = [ fractalification_iteration( submob, dimension, num_inserted_anchors_range) for submob in vmobject.submobjects ] return vmobject
def interpolate_submobject(self, submob: VMobject, start: VMobject, alpha: float) -> None: submob.set_stroke( opacity=interpolate(0, start.get_stroke_opacity(), alpha)) submob.set_fill( opacity=interpolate(0, start.get_fill_opacity(), alpha))
def interpolate_color(self, mobject1, mobject2, alpha): # TODO, transition between actual images? self.opacity = interpolate( mobject1.opacity, mobject2.opacity, alpha )
def func(alpha): return interpolate(start_number, target_number, alpha)
def add_spikes(self): layers = VGroup() radii = np.linspace( self.outer_radius, self.pupil_radius, self.n_spike_layers, endpoint=False, ) radii[:2] = radii[1::-1] # Swap first two radii[-1] = interpolate( radii[-1], self.pupil_radius, 0.25 ) for radius in radii: tip_angle = self.spike_angle half_base = radius * np.tan(tip_angle) triangle, right_half_triangle = [ Polygon( radius * UP, half_base * RIGHT, vertex3, fill_opacity=1, stroke_width=0, ) for vertex3 in (half_base * LEFT, ORIGIN,) ] left_half_triangle = right_half_triangle.copy() left_half_triangle.flip(UP, about_point=ORIGIN) n_spikes = self.n_spikes full_spikes = [ triangle.copy().rotate( -angle, about_point=ORIGIN ) for angle in np.linspace( 0, TAU, n_spikes, endpoint=False ) ] index = (3 * n_spikes) // 4 if radius == radii[0]: layer = VGroup(*full_spikes) layer.rotate( -TAU / n_spikes / 2, about_point=ORIGIN ) layer.brown_index = index else: half_spikes = [ right_half_triangle.copy(), left_half_triangle.copy().rotate( 90 * DEGREES, about_point=ORIGIN, ), right_half_triangle.copy().rotate( 90 * DEGREES, about_point=ORIGIN, ), left_half_triangle.copy() ] layer = VGroup(*it.chain( half_spikes[:1], full_spikes[1:index], half_spikes[1:3], full_spikes[index + 1:], half_spikes[3:], )) layer.brown_index = index + 1 layers.add(layer) # Color spikes blues = self.blue_spike_colors browns = self.brown_spike_colors for layer, blue, brown in zip(layers, blues, browns): index = layer.brown_index layer[:index].set_color(blue) layer[index:].set_color(brown) self.spike_layers = layers self.add(layers)
def interpolate_color(color1, color2, alpha): rgb = interpolate(color_to_rgb(color1), color_to_rgb(color2), alpha) return rgb_to_color(rgb)
def add_spikes(self): layers = VGroup() radii = np.linspace( self.outer_radius, self.pupil_radius, self.n_spike_layers, endpoint=False, ) radii[:2] = radii[1::-1] # Swap first two if self.n_spike_layers > 2: radii[-1] = interpolate(radii[-1], self.pupil_radius, 0.25) for radius in radii: tip_angle = self.spike_angle half_base = radius * np.tan(tip_angle) triangle, right_half_triangle = [ Polygon( radius * UP, half_base * RIGHT, vertex3, fill_opacity=1, stroke_width=0, ) for vertex3 in ( half_base * LEFT, ORIGIN, ) ] left_half_triangle = right_half_triangle.copy() left_half_triangle.flip(UP, about_point=ORIGIN) n_spikes = self.n_spikes full_spikes = [ triangle.copy().rotate(-angle, about_point=ORIGIN) for angle in np.linspace(0, TAU, n_spikes, endpoint=False) ] index = (3 * n_spikes) // 4 if radius == radii[0]: layer = VGroup(*full_spikes) layer.rotate(-TAU / n_spikes / 2, about_point=ORIGIN) layer.brown_index = index else: half_spikes = [ right_half_triangle.copy(), left_half_triangle.copy().rotate( 90 * DEGREES, about_point=ORIGIN, ), right_half_triangle.copy().rotate( 90 * DEGREES, about_point=ORIGIN, ), left_half_triangle.copy() ] layer = VGroup(*it.chain( half_spikes[:1], full_spikes[1:index], half_spikes[1:3], full_spikes[index + 1:], half_spikes[3:], )) layer.brown_index = index + 1 layers.add(layer) # Color spikes blues = self.blue_spike_colors browns = self.brown_spike_colors for layer, blue, brown in zip(layers, blues, browns): index = layer.brown_index layer[:index].set_color(blue) layer[index:].set_color(brown) self.spike_layers = layers self.add(layers)
def interpolate_color(self, mobject1, mobject2, alpha): assert(mobject1.pixel_array.shape == mobject2.pixel_array.shape) self.pixel_array = interpolate( mobject1.pixel_array, mobject2.pixel_array, alpha ).astype(self.pixel_array_dtype)
def interpolate_color(color1: ManimColor, color2: ManimColor, alpha: float) -> Color: rgb = interpolate(color_to_rgb(color1), color_to_rgb(color2), alpha) return rgb_to_color(rgb)
def interpolate_color(self, mobject1, mobject2, alpha): self.rgbas = interpolate( mobject1.rgbas, mobject2.rgbas, alpha )
def do_45_phase_shift(self, _, alpha): alpha = interpolate(0, 1 / 8, alpha) x_point, y_point = self.comp_point(alpha) self.y_vector.put_start_and_end_on(ORIGIN, y_point * UP) self.xy_vector.put_start_and_end_on(ORIGIN, y_point * UP + 2 * RIGHT)
def update_curve(c, dt): alpha = interpolate(1, 4, dt) c_c = FunctionGraph(lambda x: 2 * np.exp(-2 * (x - a * alpha)**2)) c.become(c_c)
def parameterized_function(alpha): x = interpolate(x_min, x_max, alpha) y = func(x) if not np.isfinite(y): y = self.y_max return self.coords_to_point(x, y)
def interpolate_color(color1, color2, alpha): ''' 在color1和color2之间插值,返回Color类表示的颜色 ''' rgb = interpolate(color_to_rgb(color1), color_to_rgb(color2), alpha) return rgb_to_color(rgb)
def update_submobject(self, submobject, starting_submobject, alpha): submobject.set_stroke(opacity=interpolate( 0, starting_submobject.get_stroke_opacity(), alpha)) submobject.set_fill(opacity=interpolate( 0, starting_submobject.get_fill_opacity(), alpha))
def interpolate_color(self, mobject1, mobject2, alpha): self.rgbas = interpolate(mobject1.rgbas, mobject2.rgbas, alpha)
def number_to_point(self, number): alpha = float(number - self.x_min) / (self.x_max - self.x_min) return interpolate(self.get_start(), self.get_end(), alpha)
def fade_to(self, color, alpha): self.rgbas = interpolate(self.rgbas, color_to_rgba(color), alpha) for mob in self.submobjects: mob.fade_to(color, alpha) return self
def interpolate_color(self, mobject1, mobject2, alpha): assert (mobject1.pixel_array.shape == mobject2.pixel_array.shape) self.pixel_array = interpolate(mobject1.pixel_array, mobject2.pixel_array, alpha).astype(self.pixel_array_dtype)
def number_to_point(self, number): alpha = float(number - self.x_min) / (self.x_max - self.x_min) return interpolate( self.get_start(), self.get_end(), alpha )
def __init__(self, decimal_mob: DecimalNumber, target_number: float | complex, **kwargs): start_number = decimal_mob.number super().__init__(decimal_mob, lambda a: interpolate(start_number, target_number, a), **kwargs)
def random_bright_color(): color = random_color() curr_rgb = color_to_rgb(color) new_rgb = interpolate(curr_rgb, np.ones(len(curr_rgb)), 0.5) return Color(rgb=new_rgb)
def interpolate_submobject(self, submob, start, alpha): submob.set_stroke( opacity=interpolate(0, start.get_stroke_opacity(), alpha)) submob.set_fill( opacity=interpolate(0, start.get_fill_opacity(), alpha))
def get_bounds(self, alpha): ratio = self.start_ratio a = interpolate((1 - ratio) / 4, 1 / 2 + ratio / 4, alpha) b = interpolate((1 - ratio) / 4, 3 / 2 + ratio / 4, alpha) return (a, b)
def __init__(self, decimal_mob, target_number, **kwargs): start_number = decimal_mob.number super().__init__(decimal_mob, lambda a: interpolate(start_number, target_number, a), **kwargs)