def scale(self, factor, **kwargs): if self.get_length() == 0: return self has_tip = self.has_tip() has_start_tip = self.has_start_tip() if has_tip or has_start_tip: old_tips = self.pop_tips() VMobject.scale(self, factor, **kwargs) self.set_stroke_width_from_length() # So horribly confusing, must redo if has_tip: self.add_tip() old_tips[0].points[:, :] = self.tip.points self.remove(self.tip) self.tip = old_tips[0] self.add(self.tip) if has_start_tip: self.add_tip(at_start=True) old_tips[1].points[:, :] = self.start_tip.points self.remove(self.start_tip) self.start_tip = old_tips[1] self.add(self.start_tip) return self
def init_colors(self): VMobject.init_colors(self) internal_pis = [ pi for pi in self.get_family() if isinstance(pi, PiCreature) ] random.seed(self.random_seed) for pi in reversed(internal_pis): color = random.choice(self.colors) pi.set_color(color) pi.set_stroke(color, width=0)
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 scale(self, factor, **kwargs): has_tip = self.has_tip() has_start_tip = self.has_start_tip() if has_tip or has_start_tip: self.pop_tips() VMobject.scale(self, factor, **kwargs) self.set_stroke_width_from_length() if has_tip: self.add_tip() if has_start_tip: self.add_tip(at_start=True) return self
def __init__(self, t_func: Callable[[float], np.ndarray], t_range: Sequence[float] | None = None, **kwargs): digest_config(self, kwargs) if t_range is not None: self.t_range[:len(t_range)] = t_range # To be backward compatible with all the scenes specifying t_min, t_max, step_size self.t_range = [ kwargs.get("t_min", self.t_range[0]), kwargs.get("t_max", self.t_range[1]), kwargs.get("step_size", self.t_range[2]), ] self.t_func = t_func VMobject.__init__(self, **kwargs)
def __init__(self, svg_string=None, **kwargs): #### EULERTOUR_INIT_START #### if not hasattr(self, "args"): self.args = serialize_args([]) if not hasattr(self, "config"): self.config = serialize_config({ 'svg_string': svg_string, **kwargs, }) #### EULERTOUR_INIT_START #### digest_config(self, kwargs) self.svg_string = svg_string or self.svg_string assert (self.svg_string is not None) VMobject.__init__(self, **kwargs) self.move_into_position()
def __init__(self, path_string, **kwargs): #### EULERTOUR_INIT_START #### if not hasattr(self, "args"): self.args = serialize_args([path_string]) if not hasattr(self, "config"): self.config = serialize_config({ **kwargs, }) if hasattr(self, 'kwargs'): self.kwargs = {'path_string': path_string, **kwargs, **self.kwargs} else: self.kwargs = {'path_string': path_string, **kwargs} #### EULERTOUR_INIT_START #### digest_locals(self) VMobject.__init__(self, **kwargs)
def __init__(self, **kwargs): #### EULERTOUR_INIT_START #### if not hasattr(self, "args"): self.args = serialize_args([]) if not hasattr(self, "config"): self.config = serialize_config({ **kwargs, }) #### EULERTOUR_INIT_START #### VMobject.__init__(self, **kwargs) self.set_points_as_corners([UP, UP + RIGHT, RIGHT]) self.set_width(self.width, about_point=ORIGIN) self.rotate(self.angle, about_point=ORIGIN) #### EULERTOUR_INIT_END #### register_mobject(self)
def __init__(self, vmobject: VMobject, **kwargs): digest_config(self, kwargs) max_stroke_width = vmobject.get_stroke_width() max_time_width = kwargs.pop("time_width", self.time_width) AnimationGroup.__init__(self, *[ VShowPassingFlash( vmobject.copy().set_stroke(width=stroke_width), time_width=time_width, **kwargs ) for stroke_width, time_width in zip( np.linspace(0, max_stroke_width, self.n_segments), np.linspace(max_time_width, 0, self.n_segments) ) ])
def __init__(self, **kwargs): digest_config(self, kwargs) self.pdfunction = normal_pdf if not self.set_up_the_bot_curve: self.num_of_anchor_in_bottom_curve = 0 #determin x_max and x_min side_probability = (1. - self.confidence_interval) / 2 self.x_max = self.std * (inverse_of_normal_cdf( side_probability + self.confidence_interval)) + self.mean self.x_min = self.std * ( inverse_of_normal_cdf(side_probability)) + self.mean VMobject.__init__(self, **kwargs) self.highest_points = self.get_highest_point()
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 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 __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 __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 set_style_data(self, stroke_color=None, stroke_width=None, fill_color=None, fill_opacity=None, family=True ): # Unchangable style, except for fill_opacity VMobject.set_style_data( self, stroke_color=BLACK, stroke_width=0, fill_color=BLACK, fill_opacity=fill_opacity ) return self
def __init__(self, start=LEFT, end=RIGHT, **kwargs): #### EULERTOUR_INIT_START #### if not hasattr(self, "args"): self.args = serialize_args([]) if not hasattr(self, "config"): self.config = serialize_config({ 'start': start, 'end': end, **kwargs, }) #### EULERTOUR_INIT_START #### digest_config(self, kwargs) self.set_start_and_end_attrs(start, end) VMobject.__init__(self, **kwargs) #### EULERTOUR_INIT_END #### register_mobject(self)
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 scale(self, factor, **kwargs): has_tip = self.has_tip() has_start_tip = self.has_start_tip() if has_tip or has_start_tip: old_tips = self.pop_tips() VMobject.scale(self, factor, **kwargs) self.set_stroke_width_from_length() if has_tip: self.add_tip() self.tip.match_style(old_tips[0]) if has_start_tip: self.add_tip(at_start=True) self.start_tip.match_style(old_tips[1]) return self
def set_style_data(self, stroke_color=None, stroke_width=None, fill_color=None, fill_opacity=None, family=True ): # Unchangable style, except for fill_opacity VMobject.set_style_data( self, stroke_color=BLACK, stroke_width=0, fill_color=BLACK, fill_opacity=fill_opacity ) return self
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_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 __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 __init__(self, vmobject: VMobject, **kwargs): assert(isinstance(vmobject, VMobject)) self.sm_to_index = dict([ (hash(sm), 0) for sm in vmobject.get_family() ]) super().__init__(vmobject, **kwargs)
def __init__(self, start_angle=0, angle=TAU / 4, **kwargs): #### EULERTOUR_INIT_START #### if not hasattr(self, "args"): self.args = serialize_args([]) if not hasattr(self, "config"): self.config = serialize_config({ 'start_angle': start_angle, 'angle': angle, **kwargs, }) #### EULERTOUR_INIT_START #### self.start_angle = start_angle self.angle = angle VMobject.__init__(self, **kwargs) #### EULERTOUR_INIT_END #### register_mobject(self)
def __init__(self, chem, name, name_direction=DOWN, **kwargs): VMobject.__init__(self, **kwargs) if isinstance(chem, ChemObject): self.chem = chem else: self.chem = ChemObject(chem, **kwargs) if isinstance(name, self.label_constructor): self.name = name else: self.name = self.label_constructor(name, **kwargs) self.name.next_to(self.chem, name_direction, buff=self.buff) self.submobjects = [self.chem, self.name]
def set_style_data( self, stroke_color: ManimColor | None = None, stroke_width: float | None = None, fill_color: ManimColor | None = None, fill_opacity: float | None = None, family: bool = True ): # Unchangeable style, except for fill_opacity VMobject.set_style_data( self, stroke_color=BLACK, stroke_width=0, fill_color=BLACK, fill_opacity=fill_opacity ) return self
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, tex_string, **kwargs): #### EULERTOUR_INIT_START #### if not hasattr(self, "args"): self.args = serialize_args([tex_string]) if not hasattr(self, "config"): self.config = serialize_config({ **kwargs, }) if hasattr(self, 'kwargs'): self.kwargs = {'tex_string': tex_string, **kwargs, **self.kwargs} else: self.kwargs = {'tex_string': tex_string, **kwargs} #### EULERTOUR_INIT_START #### digest_config(self, kwargs) assert (isinstance(tex_string, str)) self.tex_string = tex_string VMobject.__init__(self, **kwargs)
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 __init__(self, *vertices, **kwargs): VMobject.__init__(self, **kwargs) self.set_points_as_corners([*vertices, vertices[0]]) x, y = [], [] for i in range(len(vertices)): x.append(vertices[i][0]) y.append(vertices[i][1]) self.x = np.asfarray(x) self.y = np.asfarray(y) # Closes the polygon if were open if x[0] != x[-1] or y[0] != y[-1]: self.x = np.concatenate((self.x, [x[0]])) self.y = np.concatenate((self.y, [y[0]])) # Forced anti-clockwise coordinates if self._det(self.x, self.y) < 0: self.x = self.x[::-1] self.y = self.y[::-1]
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 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 set_default_config_from_length(self, vmobject: VMobject) -> None: length = len(vmobject.family_members_with_points()) if self.run_time is None: if length < 15: self.run_time = 1 else: self.run_time = 2 if self.lag_ratio is None: self.lag_ratio = min(4.0 / (length + 1.0), 0.2)
def __init__(self, matrix, **kwargs): """ Matrix can either either include numbres, tex_strings, or mobjects """ VMobject.__init__(self, **kwargs) matrix = np.array(matrix, ndmin=1) mob_matrix = self.matrix_to_mob_matrix(matrix) self.organize_mob_matrix(mob_matrix) self.elements = VGroup(*mob_matrix.flatten()) self.add(self.elements) self.add_brackets() self.center() self.mob_matrix = mob_matrix if self.add_background_rectangles_to_entries: for mob in self.elements: mob.add_background_rectangle() if self.include_background_rectangle: self.add_background_rectangle()
def show_ghost_movement(self, vector): 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 __init__(self, **kwargs): SVGMobject.__init__(self, **kwargs) path = self.submobjects[0] subpaths = path.get_subpaths() path.clear_points() for indices in [(0, 1), (2, 3), (4, 6, 7), (5,), (8,)]: part = VMobject() for index in indices: part.append_points(subpaths[index]) path.add(part) self.set_height(self.height) self.set_stroke(color=WHITE, width=0) self.set_fill(self.color, opacity=1) from manimlib.for_3b1b_videos.pi_creature import Randolph randy = Randolph(mode="happy") randy.set_height(0.6 * self.get_height()) randy.stretch(0.8, 0) randy.look(RIGHT) randy.move_to(self) randy.shift(0.07 * self.height * (RIGHT + UP)) self.randy = self.pi_creature = randy self.add_to_back(randy) orientation_line = Line(self.get_left(), self.get_right()) orientation_line.set_stroke(width=0) self.add(orientation_line) self.orientation_line = orientation_line for light, color in zip(self.get_lights(), self.light_colors): light.set_fill(color, 1) light.is_subpath = False self.add_treds_to_tires()
def generate_points(self): self.add(self.source_point) self.lighthouse = Lighthouse() self.ambient_light = AmbientLight( source_point=VectorizedPoint(location=self.get_source_point()), color=self.color, num_levels=self.num_levels, radius=self.radius, opacity_function=self.opacity_function, max_opacity=self.max_opacity_ambient ) if self.has_screen(): self.spotlight = Spotlight( source_point=VectorizedPoint(location=self.get_source_point()), color=self.color, num_levels=self.num_levels, radius=self.radius, screen=self.screen, opacity_function=self.opacity_function, max_opacity=self.max_opacity_spotlight, camera_mob=self.camera_mob ) else: self.spotlight = Spotlight() self.shadow = VMobject(fill_color=SHADOW_COLOR, fill_opacity=1.0, stroke_color=BLACK) self.lighthouse.next_to(self.get_source_point(), DOWN, buff=0) self.ambient_light.move_source_to(self.get_source_point()) if self.has_screen(): self.spotlight.move_source_to(self.get_source_point()) self.update_shadow() self.add(self.ambient_light, self.spotlight, self.lighthouse, self.shadow)
def __init__(self, func, **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)
def __init__(self, *vertices, **kwargs): VMobject.__init__(self, **kwargs) self.set_points_as_corners( [*vertices, vertices[0]] )
def __init__(self, body, **kwargs): VMobject.__init__(self, **kwargs) self.body = body eyes = self.create_eyes() self.become(eyes, copy_submobjects=False)
def get_center(self): result = VMobject.get_center(self) if hasattr(self, "center_offset"): result -= self.center_offset return result
def __init__(self, **kwargs): VMobject.__init__(self, **kwargs) self.add_iris_back() self.add_spikes() self.add_pupil()
def __init__(self, file_name=None, **kwargs): digest_config(self, kwargs) self.file_name = file_name or self.file_name self.ensure_valid_file() VMobject.__init__(self, **kwargs) self.move_into_position()
def update_shadow(self): point = self.get_source_point() projected_screen_points = [] if not self.has_screen(): return for point in self.screen.get_anchors(): projected_screen_points.append(self.spotlight.project(point)) projected_source = project_along_vector( self.get_source_point(), self.spotlight.projection_direction()) projected_point_cloud_3d = np.append( projected_screen_points, np.reshape(projected_source, (1, 3)), axis=0 ) # z_to_vector(self.spotlight.projection_direction()) rotation_matrix = self.rotation_matrix() back_rotation_matrix = rotation_matrix.T # i. e. its inverse rotated_point_cloud_3d = np.dot( projected_point_cloud_3d, back_rotation_matrix.T) # these points now should all have z = 0 point_cloud_2d = rotated_point_cloud_3d[:, :2] # now we can compute the convex hull hull_2d = ConvexHull(point_cloud_2d) # guaranteed to run ccw hull = [] # we also need the projected source point source_point_2d = np.dot(self.spotlight.project( self.get_source_point()), back_rotation_matrix.T)[:2] index = 0 for point in point_cloud_2d[hull_2d.vertices]: if np.all(np.abs(point - source_point_2d) < 1.0e-6): source_index = index index += 1 continue point_3d = np.array([point[0], point[1], 0]) hull.append(point_3d) index += 1 hull_mobject = VMobject() hull_mobject.set_points_as_corners(hull) hull_mobject.apply_matrix(rotation_matrix) anchors = hull_mobject.get_anchors() # add two control points for the outer cone if np.size(anchors) == 0: self.shadow.points = [] return ray1 = anchors[source_index - 1] - projected_source ray1 = ray1 / get_norm(ray1) * 100 ray2 = anchors[source_index] - projected_source ray2 = ray2 / get_norm(ray2) * 100 outpoint1 = anchors[source_index - 1] + ray1 outpoint2 = anchors[source_index] + ray2 new_anchors = anchors[:source_index] new_anchors = np.append(new_anchors, np.array( [outpoint1, outpoint2]), axis=0) new_anchors = np.append(new_anchors, anchors[source_index:], axis=0) self.shadow.set_points_as_corners(new_anchors) # shift it closer to the camera so it is in front of the spotlight self.shadow.mark_paths_closed = True
def __init__(self, start_angle=0, angle=TAU / 4, **kwargs): self.start_angle = start_angle self.angle = angle VMobject.__init__(self, **kwargs)
def get_start(self): if self.has_start_tip(): return self.start_tip.get_start() else: return VMobject.get_start(self)
class LightSource(VMobject): # combines: # a lighthouse # an ambient light # a spotlight # and a shadow CONFIG = { "source_point": VectorizedPoint(location=ORIGIN, stroke_width=0, fill_opacity=0), "color": LIGHT_COLOR, "num_levels": 10, "radius": 10.0, "screen": None, "opacity_function": inverse_quadratic(1, 2, 1), "max_opacity_ambient": AMBIENT_FULL, "max_opacity_spotlight": SPOTLIGHT_FULL, "camera_mob": None } def generate_points(self): self.add(self.source_point) self.lighthouse = Lighthouse() self.ambient_light = AmbientLight( source_point=VectorizedPoint(location=self.get_source_point()), color=self.color, num_levels=self.num_levels, radius=self.radius, opacity_function=self.opacity_function, max_opacity=self.max_opacity_ambient ) if self.has_screen(): self.spotlight = Spotlight( source_point=VectorizedPoint(location=self.get_source_point()), color=self.color, num_levels=self.num_levels, radius=self.radius, screen=self.screen, opacity_function=self.opacity_function, max_opacity=self.max_opacity_spotlight, camera_mob=self.camera_mob ) else: self.spotlight = Spotlight() self.shadow = VMobject(fill_color=SHADOW_COLOR, fill_opacity=1.0, stroke_color=BLACK) self.lighthouse.next_to(self.get_source_point(), DOWN, buff=0) self.ambient_light.move_source_to(self.get_source_point()) if self.has_screen(): self.spotlight.move_source_to(self.get_source_point()) self.update_shadow() self.add(self.ambient_light, self.spotlight, self.lighthouse, self.shadow) def has_screen(self): if self.screen is None: return False elif np.size(self.screen.points) == 0: return False else: return True def dim_ambient(self): self.set_max_opacity_ambient(AMBIENT_DIMMED) def set_max_opacity_ambient(self, new_opacity): self.max_opacity_ambient = new_opacity self.ambient_light.dimming(new_opacity) def dim_spotlight(self): self.set_max_opacity_spotlight(SPOTLIGHT_DIMMED) def set_max_opacity_spotlight(self, new_opacity): self.max_opacity_spotlight = new_opacity self.spotlight.dimming(new_opacity) def set_camera_mob(self, new_cam_mob): self.camera_mob = new_cam_mob self.spotlight.camera_mob = new_cam_mob def set_screen(self, new_screen): if self.has_screen(): self.spotlight.screen = new_screen else: # Note: See below index = self.submobjects.index(self.spotlight) # camera_mob = self.spotlight.camera_mob self.remove(self.spotlight) self.spotlight = Spotlight( source_point=VectorizedPoint(location=self.get_source_point()), color=self.color, num_levels=self.num_levels, radius=self.radius, screen=new_screen, camera_mob=self.camera_mob, opacity_function=self.opacity_function, max_opacity=self.max_opacity_spotlight, ) self.spotlight.move_source_to(self.get_source_point()) # Note: This line will make spotlight show up at the end # of the submojects list, which can make it show up on # top of the shadow. To make it show up in the # same spot, you could try the following line, # where "index" is what I defined above: self.submobjects.insert(index, self.spotlight) # self.add(self.spotlight) # in any case self.screen = new_screen def move_source_to(self, point): apoint = np.array(point) v = apoint - self.get_source_point() # Note: As discussed, things stand to behave better if source # point is a submobject, so that it automatically interpolates # during an animation, and other updates can be defined wrt # that source point's location self.source_point.set_location(apoint) # self.lighthouse.next_to(apoint,DOWN,buff = 0) # self.ambient_light.move_source_to(apoint) self.lighthouse.shift(v) # self.ambient_light.shift(v) self.ambient_light.move_source_to(apoint) if self.has_screen(): self.spotlight.move_source_to(apoint) self.update() return self def change_spotlight_opacity_function(self, new_of): self.spotlight.change_opacity_function(new_of) def set_radius(self, new_radius): self.radius = new_radius self.ambient_light.radius = new_radius self.spotlight.radius = new_radius def update(self): self.update_lighthouse() self.update_ambient() self.spotlight.update_sectors() self.update_shadow() def update_lighthouse(self): self.lighthouse.move_to(self.get_source_point()) # new_lh = Lighthouse() # new_lh.move_to(ORIGIN) # new_lh.apply_matrix(self.rotation_matrix()) # new_lh.shift(self.get_source_point()) # self.lighthouse.submobjects = new_lh.submobjects def update_ambient(self): new_ambient_light = AmbientLight( source_point=VectorizedPoint(location=ORIGIN), color=self.color, num_levels=self.num_levels, radius=self.radius, opacity_function=self.opacity_function, max_opacity=self.max_opacity_ambient ) new_ambient_light.apply_matrix(self.rotation_matrix()) new_ambient_light.move_source_to(self.get_source_point()) self.ambient_light.submobjects = new_ambient_light.submobjects def get_source_point(self): return self.source_point.get_location() def rotation_matrix(self): if self.camera_mob is None: return np.eye(3) phi = self.camera_mob.get_center()[0] theta = self.camera_mob.get_center()[1] R1 = np.array([ [1, 0, 0], [0, np.cos(phi), -np.sin(phi)], [0, np.sin(phi), np.cos(phi)] ]) R2 = np.array([ [np.cos(theta + TAU / 4), -np.sin(theta + TAU / 4), 0], [np.sin(theta + TAU / 4), np.cos(theta + TAU / 4), 0], [0, 0, 1] ]) R = np.dot(R2, R1) return R def update_shadow(self): point = self.get_source_point() projected_screen_points = [] if not self.has_screen(): return for point in self.screen.get_anchors(): projected_screen_points.append(self.spotlight.project(point)) projected_source = project_along_vector( self.get_source_point(), self.spotlight.projection_direction()) projected_point_cloud_3d = np.append( projected_screen_points, np.reshape(projected_source, (1, 3)), axis=0 ) # z_to_vector(self.spotlight.projection_direction()) rotation_matrix = self.rotation_matrix() back_rotation_matrix = rotation_matrix.T # i. e. its inverse rotated_point_cloud_3d = np.dot( projected_point_cloud_3d, back_rotation_matrix.T) # these points now should all have z = 0 point_cloud_2d = rotated_point_cloud_3d[:, :2] # now we can compute the convex hull hull_2d = ConvexHull(point_cloud_2d) # guaranteed to run ccw hull = [] # we also need the projected source point source_point_2d = np.dot(self.spotlight.project( self.get_source_point()), back_rotation_matrix.T)[:2] index = 0 for point in point_cloud_2d[hull_2d.vertices]: if np.all(np.abs(point - source_point_2d) < 1.0e-6): source_index = index index += 1 continue point_3d = np.array([point[0], point[1], 0]) hull.append(point_3d) index += 1 hull_mobject = VMobject() hull_mobject.set_points_as_corners(hull) hull_mobject.apply_matrix(rotation_matrix) anchors = hull_mobject.get_anchors() # add two control points for the outer cone if np.size(anchors) == 0: self.shadow.points = [] return ray1 = anchors[source_index - 1] - projected_source ray1 = ray1 / get_norm(ray1) * 100 ray2 = anchors[source_index] - projected_source ray2 = ray2 / get_norm(ray2) * 100 outpoint1 = anchors[source_index - 1] + ray1 outpoint2 = anchors[source_index] + ray2 new_anchors = anchors[:source_index] new_anchors = np.append(new_anchors, np.array( [outpoint1, outpoint2]), axis=0) new_anchors = np.append(new_anchors, anchors[source_index:], axis=0) self.shadow.set_points_as_corners(new_anchors) # shift it closer to the camera so it is in front of the spotlight self.shadow.mark_paths_closed = True
def __init__(self, start=LEFT, end=RIGHT, **kwargs): digest_config(self, kwargs) self.set_start_and_end_attrs(start, end) VMobject.__init__(self, **kwargs)
def __init__(self, path_string, **kwargs): digest_locals(self) VMobject.__init__(self, **kwargs)
def init_colors(self): VMobject.init_colors(self) self.set_color_by_gradient(*self.colors)
def __init__(self, **kwargs): VMobject.__init__(self, **kwargs) self.set_points_as_corners([UP, UP + RIGHT, RIGHT]) self.set_width(self.width, about_point=ORIGIN) self.rotate(self.angle, about_point=ORIGIN)
def __init__(self, points, **kwargs): VMobject.__init__(self, **kwargs) self.set_points(points)
def init_colors(self): VMobject.init_colors(self) self.set_color_by_gradient(*self.colors) for order in sorted(self.order_to_stroke_width_map.keys()): if self.order >= order: self.set_stroke(width=self.order_to_stroke_width_map[order])