def init_points(self) -> None: uv_surface = self.uv_surface full_nu, full_nv = uv_surface.resolution part_nu, part_nv = self.resolution # 'indices' are treated as floats. Later, there will be # an interpolation between the floor and ceiling of these # indices u_indices = np.linspace(0, full_nu - 1, part_nu) v_indices = np.linspace(0, full_nv - 1, part_nv) points, du_points, dv_points = uv_surface.get_surface_points_and_nudged_points( ) normals = uv_surface.get_unit_normals() nudge = self.normal_nudge nudged_points = points + nudge * normals for ui in u_indices: path = VMobject() low_ui = full_nv * int(math.floor(ui)) high_ui = full_nv * int(math.ceil(ui)) path.set_points_smoothly( interpolate(nudged_points[low_ui:low_ui + full_nv], nudged_points[high_ui:high_ui + full_nv], ui % 1)) self.add(path) for vi in v_indices: path = VMobject() path.set_points_smoothly( interpolate(nudged_points[int(math.floor(vi))::full_nv], nudged_points[int(math.ceil(vi))::full_nv], vi % 1)) self.add(path)
def construct(self): # Generate transformation animations of the twin dragon curve anims = list() fractal = VMobject() fractal.shift(UP) for order in range(-1, self.max_order+1): new_fractal = TwinDragon(order = order) new_fractal.shift(UP) run_time = 0.5 if order >= 0 else 0 anims.append( Transform( fractal, new_fractal, submobject_mode = "all_at_once", run_time = run_time, ) ) fractal = new_fractal # Add the channel name text = TextMobject("Solara570") text.scale(2).to_edge(DOWN, buff = 1.2) # Now sit back and watch self.play( Succession(*anims, rate_func = smooth), Write(text, lag_factor = 2.5, rate_func = squish_rate_func(smooth, 0.1, 0.9)), run_time = 4.5, )
def get_fourier_graph(self, axes, time_func, t_min, t_max, n_samples = NUM_SAMPLES_FOR_FFT, complex_to_real_func = lambda z : z.real, color = RED, ): # N = n_samples # T = time_range/n_samples time_range = float(t_max - t_min) time_step_size = time_range/n_samples time_samples = np.vectorize(time_func)(np.linspace(t_min, t_max, n_samples)) fft_output = np.fft.fft(time_samples) frequencies = np.linspace(0.0, n_samples/(2.0*time_range), n_samples//2) # #Cycles per second of fouier_samples[1] # (1/time_range)*n_samples # freq_step_size = 1./time_range graph = VMobject() graph.set_points_smoothly([ axes.coords_to_point( x, complex_to_real_func(y)/n_samples, ) for x, y in zip(frequencies, fft_output[:n_samples//2]) ]) graph.set_color(color) f_min, f_max = [ axes.x_axis.point_to_number(graph.points[i]) for i in (0, -1) ] graph.underlying_function = lambda f : axes.y_axis.point_to_number( graph.point_from_proportion((f - f_min)/(f_max - f_min)) ) return graph
def shift_brace(self, obj: VMobject | list[VMobject], **kwargs): if isinstance(obj, list): obj = VMobject(*obj) self.brace = Brace(obj, self.brace_direction, **kwargs) self.brace.put_at_tip(self.label) self.submobjects[0] = self.brace return self
def draw_lines(self): lines = [] origin = self.coordinate_system.get_origin() for point in self.get_start_points(): points = [point] total_arc_len = 0 time = 0 for x in range(self.max_time_steps): time += self.dt last_point = points[-1] new_point = last_point + self.dt * ( self.point_func(last_point) - origin) points.append(new_point) total_arc_len += get_norm(new_point - last_point) if get_norm(last_point) > self.cutoff_norm: break if total_arc_len > self.arc_len: break line = VMobject() line.virtual_time = time step = max(1, int(len(points) / self.n_samples_per_line)) line.set_points_as_corners(points[::step]) line.make_approximately_smooth() lines.append(line) self.set_submobjects(lines)
def get_dashed_rectangle(self, width, height): h1 = [ORIGIN, UP * height] w1 = [UP * height, UP * height + RIGHT * width] h2 = [UP * height + RIGHT * width, RIGHT * width] w2 = [RIGHT * width, ORIGIN] alpha = width / height divs = self.num_dashes n_h = int(divs / (2 * (alpha + 1))) n_w = int(alpha * n_h) dashedrectangle = VGroup() for n, l in zip([n_w, n_h], [[w1, w2], [h1, h2]]): for side in l: line = VMobject() line.set_points_as_corners(side) dashedrectangle.add( DashedVMobject( line, num_dashes=n, positive_space_ratio=self.positive_space_ratio, ).set_color(self.color).set_style(**self.line_config)) return [ dashedrectangle[0], dashedrectangle[3], dashedrectangle[1], dashedrectangle[2] ]
def get_label_by_fraction(self, p, q, thres = 1e-6): x = p/q for label in self.labels: lx = self.axes.point_to_coords(label.get_center())[0] if np.abs(x - lx) < thres: return label return VMobject()
def use_to_mobjects(self, use_element): # Remove initial "#" character ref = use_element.getAttribute("xlink:href")[1:] if ref not in self.ref_to_element: warnings.warn("%s not recognized" % ref) return VMobject() return self.get_mobjects_from(self.ref_to_element[ref])
def get_circle_by_fraction(self, p, q, thres = 1e-6): x = p/q for circle in self.circles: cx = self.axes.point_to_coords(circle.get_center())[0] if np.abs(x - cx) < thres: return circle return VMobject()
def __init__(self, *args, func=AnimateStroke, run_time=None, fix_time=None, lag_ratio=0,**kwargs): animations=AGroup() runtime={} fixtime={} if isinstance(args[-1], (int,float)): if args[-1]>=0: runtime.update({'run_time':args[-1]}) else: fixtime.update({'run_time':-args[-1]}) args=args[:-1] if run_time is not None: runtime.update({'runtime':runtime}) if fix_time is not None: fixtime.update({'fix_time':fix_time}) for arg in args: kws={} if isinstance(arg[-1], dict): kws=arg[-1] arg=arg[:-1] kws.update(fixtime) kws.update(kwargs) mobj=VMobject() for each in arg: if isinstance(arg[0],(Mobject,Group,VMobject,VGroup)): mobj.add(arg[0]) arg=arg[1:] animations.add(func(mobj,*arg,**kws)) super().__init__(*animations,lag_ratio=lag_ratio,**runtime)
def prtV(self, arg=None): from manimlib.mobject.types.vectorized_mobject import VMobject if arg is None: print(self) else: print(arg) return VMobject()
def check_and_fix_percent_bug(sym): # This is an ugly patch addressing something which should be # addressed at a deeper level. # The svg path for percent symbols have a known bug, so this # checks if the symbol is (probably) a percentage sign, and # splits it so that it's displayed properly. if len(sym.get_points()) not in [315, 324, 372, 468, 483] or len(sym.get_subpaths()) != 4: return sym = sym.family_members_with_points()[0] new_sym = VMobject() path_lengths = [len(path) for path in sym.get_subpaths()] sym_points = sym.get_points() if len(sym_points) in [315, 324, 372]: n = sum(path_lengths[:2]) p1 = sym_points[:n] p2 = sym_points[n:] elif len(sym_points) in [468, 483]: p1 = np.vstack([ sym_points[:path_lengths[0]], sym_points[-path_lengths[3]:] ]) p2 = sym_points[path_lengths[0]:sum(path_lengths[:3])] sym.set_points(p1) new_sym.set_points(p2) sym.add(new_sym) sym.refresh_triangulation()
def show_ghost_movement(self, vector): """ This method plays an animation that partially shows the entire plane moving in the direction of a particular vector. This is useful when you wish to convey the idea of mentally moving the entire plane in a direction, without actually moving the plane. Parameters ---------- vector (Union[Arrow, list, tuple, np.ndarray]) The vector which indicates the direction of movement. """ if isinstance(vector, Arrow): vector = vector.get_end() - vector.get_start() elif len(vector) == 2: vector = np.append(np.array(vector), 0.0) x_max = int(FRAME_X_RADIUS + abs(vector[0])) y_max = int(FRAME_Y_RADIUS + abs(vector[1])) dots = VMobject(*[ Dot(x * RIGHT + y * UP) for x in range(-x_max, x_max) for y in range(-y_max, y_max) ]) dots.set_fill(BLACK, opacity=0) dots_halfway = dots.copy().shift(vector / 2).set_fill(WHITE, 1) dots_end = dots.copy().shift(vector) self.play(Transform(dots, dots_halfway, rate_func=rush_into)) self.play(Transform(dots, dots_end, rate_func=rush_from)) self.remove(dots)
def get_mobjects_from(self, element): result = [] if not isinstance(element, minidom.Element): return result if element.tagName == 'defs': self.update_ref_to_element(element) elif element.tagName == 'style': pass # TODO, handle style elif element.tagName in ['g', 'svg']: result += it.chain(*[ self.get_mobjects_from(child) for child in element.childNodes ]) elif element.tagName == 'path': result.append( self.path_string_to_mobject(element.getAttribute('d'))) elif element.tagName == 'use': result += self.use_to_mobjects(element) elif element.tagName == 'rect': result.append(self.rect_to_mobject(element)) elif element.tagName == 'circle': result.append(self.circle_to_mobject(element)) elif element.tagName == 'ellipse': result.append(self.ellipse_to_mobject(element)) elif element.tagName in ['polygon', 'polyline']: result.append(self.polygon_to_mobject(element)) else: pass # TODO # warnings.warn("Unknown element type: " + element.tagName) result = [m for m in result if m is not None] self.handle_transforms(element, VMobject(*result)) if len(result) > 1 and not self.unpack_groups: result = [VGroup(*result)] return result
def generate_points(self): full_string = f"{self.prefix}{self.tex_string}{self.suffix}" path_data = tex_to_points(full_string) for point_list in path_data: if point_list: vmob = VMobject(skip_registration=True) vmob.append_points(point_list) self.add(vmob)
def generate_points(self): if self.order < 0: return VMobject() tc = TohruCurve(order = self.order) kc = KannaCurve(order = self.order) kc.shift(tc.get_end() - kc.get_start()) group = VGroup(tc, kc).center() self.add(group)
def get_displayed(self, mobjects): mobjs = self.get_restructured_mobject_list( mobjects, self.get_restructured_mobject_list(mobjects, self.mobjects)) if mobjs: return VGroup(*mobjs) else: return VMobject()
def generate_points(self): if self.x_radius is None: center_to_edge = (FRAME_X_RADIUS + abs(self.center_point[0])) self.x_radius = center_to_edge / self.x_unit_size if self.y_radius is None: center_to_edge = (FRAME_Y_RADIUS + abs(self.center_point[1])) self.y_radius = center_to_edge / self.y_unit_size self.axes = VMobject() self.main_lines = VMobject() self.secondary_lines = VMobject() tuples = [ ( self.x_radius, self.x_line_frequency, self.y_radius * DOWN, self.y_radius * UP, RIGHT ), ( self.y_radius, self.y_line_frequency, self.x_radius * LEFT, self.x_radius * RIGHT, UP, ), ] for radius, freq, start, end, unit in tuples: main_range = np.arange(0, radius, freq) step = freq / float(freq + self.secondary_line_ratio) for v in np.arange(0, radius, step): line1 = Line(start + v * unit, end + v * unit) line2 = Line(start - v * unit, end - v * unit) if v == 0: self.axes.add(line1) elif v in main_range: self.main_lines.add(line1, line2) else: self.secondary_lines.add(line1, line2) self.add(self.secondary_lines, self.main_lines, self.axes) self.stretch(self.x_unit_size, 0) self.stretch(self.y_unit_size, 1) self.shift(self.center_point) # Put x_axis before y_axis y_axis, x_axis = self.axes.split() self.axes = VMobject(x_axis, y_axis)
def generate_points(self): anchors = np.array( [UP, np.sqrt(3) * LEFT, DOWN, np.sqrt(3) * RIGHT, UP]) / 2. * self.side_length rhombus = VMobject(**self.rhombus_config) rhombus.set_anchor_points(anchors, mode="corners") rhombus.rotate(self.angle) self.add(rhombus) self.rhombus = rhombus
def __init__(self, focus_point, **kwargs): if not hasattr(self, "args"): self.args = serialize_args([focus_point]) if not hasattr(self, "config"): self.config = serialize_config({ **kwargs, }) self.focus_point = focus_point # Initialize with blank mobject, while create_target # and create_starting_mobject handle the meat super().__init__(VMobject(), **kwargs)
def __init__(self, vmobject, depth=1.0, direction=IN, **kwargs): # At the moment, this assume stright edges super().__init__(**kwargs) vect = depth * direction self.add(vmobject.copy()) points = vmobject.get_points()[::vmobject.n_points_per_curve] for p1, p2 in adjacent_pairs(points): wall = VMobject() wall.match_style(vmobject) wall.set_points_as_corners([p1, p2, p2 + vect, p1 + vect]) self.add(wall) self.add(vmobject.copy().shift(vect).reverse_points())
def add_pupil_light_spot(self, pupils): # Purely an artifact of how the SVGs were drawn. # In a perfect world, this wouldn't be needed for pupil in pupils: index = 16 sub_points = pupil.points[:index] pupil.points = pupil.points[index + 2:] circle = VMobject() circle.points = sub_points circle.set_stroke(width=0) circle.set_fill(WHITE, 1) pupil.add(circle)
def get_crosshair(self): line = Line(LEFT, RIGHT) line.insert_n_curves(1) lines = line.replicate(2) lines[1].rotate(PI / 2) crosshair = VMobject() crosshair.set_points([*lines[0].get_points(), *lines[1].get_points()]) crosshair.set_width(self.crosshair_width) crosshair.set_stroke(self.crosshair_color, width=[2, 0, 2, 2, 0, 2]) crosshair.set_animating_status(True) crosshair.fix_in_frame() return crosshair
def init_border(self): anchors = np.array([ [0, 0, 1], [1, 0, 1], [1, 0, 0], [1, 1, 0], [0, 1, 0], [0, 1, 1], [0, 0, 1], ]) * self.dimension border = VMobject(**self.border_config) border.set_anchor_points(anchors, mode="corners") self.border = border
def init_points(self): uv_surface = self.uv_surface full_nu, full_nv = uv_surface.resolution part_nu, part_nv = self.resolution u_indices = np.linspace(0, full_nu, part_nu).astype(int) v_indices = np.linspace(0, full_nv, part_nv).astype(int) points, du_points, dv_points = uv_surface.get_surface_points_and_nudged_points() normals = uv_surface.get_unit_normals() nudge = 1e-2 nudged_points = points + nudge * normals for ui in u_indices: path = VMobject() full_ui = full_nv * ui path.set_points_smoothly(nudged_points[full_ui:full_ui + full_nv]) self.add(path) for vi in v_indices: path = VMobject() path.set_points_smoothly(nudged_points[vi::full_nv]) self.add(path)
def __init__(self, obj: VMobject | list[VMobject], text: str | Iterable[str], brace_direction: np.ndarray = DOWN, **kwargs) -> None: VMobject.__init__(self, **kwargs) self.brace_direction = brace_direction if isinstance(obj, list): obj = VMobject(*obj) self.brace = Brace(obj, brace_direction, **kwargs) self.label = self.label_constructor(*listify(text), **kwargs) self.label.scale(self.label_scale) self.brace.put_at_tip(self.label, buff=self.label_buff) self.set_submobjects([self.brace, self.label])
def __init__(self, obj, text, brace_direction=DOWN, **kwargs): VMobject.__init__(self, **kwargs) self.brace_direction = brace_direction if isinstance(obj, list): obj = VMobject(*obj) self.brace = Brace(obj, brace_direction, **kwargs) if isinstance(text, tuple) or isinstance(text, list): self.label = self.label_constructor(*text, **kwargs) else: self.label = self.label_constructor(str(text)) if self.label_scale != 1: self.label.scale(self.label_scale) self.brace.put_at_tip(self.label) self.submobjects = [self.brace, self.label]
def add_tip(self, add_at_end=True): tip = VMobject( close_new_points=True, mark_paths_closed=True, fill_color=self.color, fill_opacity=1, stroke_color=self.color, stroke_width=0, ) tip.add_at_end = add_at_end self.set_tip_points(tip, add_at_end, preserve_normal=False) self.add(tip) if not hasattr(self, 'tip'): self.tip = VGroup() self.tip.match_style(tip) self.tip.add(tip) return tip
def __init__(self, line, count=1, posratio=0.5, length=0.3, space=0.1, **kwargs): VMobject.__init__(self, **kwargs) if not isinstance(line, VGroup): if line.get_length() <= length*5: length = min(max(0.15, line.get_length()/5), 0.3) hash = self.dimhash(line, length) hashmark = VMobject() for i in range(count): hashmark.append_vectorized_mobject(hash.copy().move_to( i*space*line.get_unit_vector() )) self.append_vectorized_mobject(hashmark.move_to( line.point_from_proportion(posratio))) else: kwargs["dimhash"] = self.dimhash self.add(Hashs(line, count=count, posratio=posratio, length=length, space=space, **kwargs))
def __init__(self, func, **kwargs): if not hasattr(self, "args"): self.args = serialize_args([func]) if not hasattr(self, "config"): self.config = serialize_config({ **kwargs, }) VGroup.__init__(self, **kwargs) self.func = func dt = self.dt start_points = self.get_start_points( **self.start_points_generator_config) for point in start_points: points = [point] for t in np.arange(0, self.virtual_time, dt): last_point = points[-1] points.append(last_point + dt * func(last_point)) if get_norm(last_point) > self.cutoff_norm: break line = VMobject() step = max(1, int(len(points) / self.n_anchors_per_line)) line.set_points_smoothly(points[::step]) self.add(line) self.set_stroke(self.stroke_color, self.stroke_width) if self.color_by_arc_length: len_to_rgb = get_rgb_gradient_function( self.min_arc_length, self.max_arc_length, colors=self.colors, ) for line in self: arc_length = line.get_arc_length() rgb = len_to_rgb([arc_length])[0] color = rgb_to_color(rgb) line.set_color(color) elif self.color_by_magnitude: image_file = get_color_field_image_file( lambda p: get_norm(func(p)), min_value=self.min_magnitude, max_value=self.max_magnitude, colors=self.colors, ) self.color_using_background_image(image_file)