Merge branch 'master' of github.com:3b1b/manim into video-work

This commit is contained in:
Grant Sanderson 2022-01-26 08:21:54 -08:00
commit 24f5a50f0b
3 changed files with 35 additions and 30 deletions

View file

@ -38,8 +38,8 @@ class _LabelledTex(SVGMobject):
color_str = "#" + "".join([c * 2 for c in color_str[1:]]) color_str = "#" + "".join([c * 2 for c in color_str[1:]])
return int(color_str[1:], 16) - 1 return int(color_str[1:], 16) - 1
def get_mobjects_from(self, element): def get_mobjects_from(self, element, style):
result = super().get_mobjects_from(element) result = super().get_mobjects_from(element, style)
for mob in result: for mob in result:
if not hasattr(mob, "glyph_label"): if not hasattr(mob, "glyph_label"):
mob.glyph_label = -1 mob.glyph_label = -1

View file

@ -35,7 +35,7 @@ DEFAULT_STYLE = {
def cascade_element_style(element, inherited): def cascade_element_style(element, inherited):
style = inherited.copy() style = inherited.copy()
for attr in DEFAULT_STYLE: for attr in DEFAULT_STYLE:
if element.hasAttribute(attr): if element.hasAttribute(attr):
style[attr] = element.getAttribute(attr) style[attr] = element.getAttribute(attr)
@ -47,13 +47,13 @@ def cascade_element_style(element, inherited):
key, value = style_spec.split(":") key, value = style_spec.split(":")
except ValueError as e: except ValueError as e:
if not style_spec.strip(): if not style_spec.strip():
pass pass
else: else:
raise e raise e
else: else:
style[key.strip()] = value.strip() style[key.strip()] = value.strip()
return style return style
def parse_color(color): def parse_color(color):
@ -66,7 +66,7 @@ def parse_color(color):
else: else:
parsed_rgbs = [int(i) / 255.0 for i in splits] parsed_rgbs = [int(i) / 255.0 for i in splits]
return rgb_to_hex(parsed_rgbs) return rgb_to_hex(parsed_rgbs)
else: else:
return web2hex(color) return web2hex(color)
@ -91,14 +91,14 @@ def parse_style(style, default_style):
manim_style["fill_opacity"] = 0 manim_style["fill_opacity"] = 0
else: else:
manim_style["fill_color"] = parse_color(style["fill"]) manim_style["fill_color"] = parse_color(style["fill"])
if style["stroke"] == "none": if style["stroke"] == "none":
manim_style["stroke_width"] = 0 manim_style["stroke_width"] = 0
if "fill_color" in manim_style: if "fill_color" in manim_style:
manim_style["stroke_color"] = manim_style["fill_color"] manim_style["stroke_color"] = manim_style["fill_color"]
else: else:
manim_style["stroke_color"] = parse_color(style["stroke"]) manim_style["stroke_color"] = parse_color(style["stroke"])
return manim_style return manim_style
@ -132,17 +132,19 @@ class SVGMobject(VMobject):
self.set_height(self.height) self.set_height(self.height)
if self.width is not None: if self.width is not None:
self.set_width(self.width) self.set_width(self.width)
def init_colors(self, override=False): def init_colors(self, override=False):
super().init_colors(override=False) super().init_colors(override=override)
def init_points(self): def init_points(self):
doc = minidom.parse(self.file_path) doc = minidom.parse(self.file_path)
self.ref_to_element = {} self.ref_to_element = {}
for child in doc.childNodes: for child in doc.childNodes:
if not isinstance(child, minidom.Element): continue if not isinstance(child, minidom.Element):
if child.tagName != 'svg': continue continue
if child.tagName != 'svg':
continue
mobjects = self.get_mobjects_from(child, dict()) mobjects = self.get_mobjects_from(child, dict())
if self.unpack_groups: if self.unpack_groups:
self.add(*mobjects) self.add(*mobjects)
@ -188,7 +190,7 @@ class SVGMobject(VMobject):
result = [VGroup(*result)] result = [VGroup(*result)]
return result return result
def generate_default_style(self): def generate_default_style(self):
style = { style = {
"fill-opacity": self.fill_opacity, "fill-opacity": self.fill_opacity,
@ -247,7 +249,7 @@ class SVGMobject(VMobject):
for key in ("cx", "cy", "r") for key in ("cx", "cy", "r")
) )
return Circle( return Circle(
radius=r, radius=r,
**parse_style(style, self.generate_default_style()) **parse_style(style, self.generate_default_style())
).shift(x * RIGHT + y * DOWN) ).shift(x * RIGHT + y * DOWN)
@ -316,10 +318,10 @@ class SVGMobject(VMobject):
mobject.shift(x * RIGHT + y * DOWN) mobject.shift(x * RIGHT + y * DOWN)
transform_names = [ transform_names = [
"matrix", "matrix",
"translate", "translateX", "translateY", "translate", "translateX", "translateY",
"scale", "scaleX", "scaleY", "scale", "scaleX", "scaleY",
"rotate", "rotate",
"skewX", "skewY" "skewX", "skewY"
] ]
transform_pattern = re.compile("|".join([x + r"[^)]*\)" for x in transform_names])) transform_pattern = re.compile("|".join([x + r"[^)]*\)" for x in transform_names]))
@ -330,7 +332,7 @@ class SVGMobject(VMobject):
op_name, op_args = transform.split("(") op_name, op_args = transform.split("(")
op_name = op_name.strip() op_name = op_name.strip()
op_args = [float(x) for x in number_pattern.findall(op_args)] op_args = [float(x) for x in number_pattern.findall(op_args)]
if op_name == "matrix": if op_name == "matrix":
self._handle_matrix_transform(mobject, op_name, op_args) self._handle_matrix_transform(mobject, op_name, op_args)
elif op_name.startswith("translate"): elif op_name.startswith("translate"):
@ -341,7 +343,7 @@ class SVGMobject(VMobject):
self._handle_rotate_transform(mobject, op_name, op_args) self._handle_rotate_transform(mobject, op_name, op_args)
elif op_name.startswith("skew"): elif op_name.startswith("skew"):
self._handle_skew_transform(mobject, op_name, op_args) self._handle_skew_transform(mobject, op_name, op_args)
def _handle_matrix_transform(self, mobject, op_name, op_args): def _handle_matrix_transform(self, mobject, op_name, op_args):
transform = np.array(op_args).reshape([3, 2]) transform = np.array(op_args).reshape([3, 2])
x = transform[2][0] x = transform[2][0]
@ -362,31 +364,31 @@ class SVGMobject(VMobject):
else: else:
x, y = op_args x, y = op_args
mobject.shift(x * RIGHT + y * DOWN) mobject.shift(x * RIGHT + y * DOWN)
def _handle_scale_transform(self, mobject, op_name, op_args): def _handle_scale_transform(self, mobject, op_name, op_args):
if op_name.endswith("X"): if op_name.endswith("X"):
sx, sy = op_args[0], 1 sx, sy = op_args[0], 1
elif op_name.endswith("Y"): elif op_name.endswith("Y"):
sx, sy = 1, op_args[0] sx, sy = 1, op_args[0]
elif len(op_args) == 2: elif len(op_args) == 2:
sx, sy = op_args sx, sy = op_args
else: else:
sx = sy = op_args[0] sx = sy = op_args[0]
if sx < 0: if sx < 0:
mobject.flip(UP) mobject.flip(UP)
sx = -sx sx = -sx
if sy < 0: if sy < 0:
mobject.flip(RIGHT) mobject.flip(RIGHT)
sy = -sy sy = -sy
mobject.scale(np.array([sx, sy, 1]), about_point=ORIGIN) mobject.scale(np.array([sx, sy, 1]), about_point=ORIGIN)
def _handle_rotate_transform(self, mobject, op_name, op_args): def _handle_rotate_transform(self, mobject, op_name, op_args):
if len(op_args) == 1: if len(op_args) == 1:
mobject.rotate(op_args[0] * DEGREES, axis=IN, about_point=ORIGIN) mobject.rotate(op_args[0] * DEGREES, axis=IN, about_point=ORIGIN)
else: else:
deg, x, y = op_args deg, x, y = op_args
mobject.rotate(deg * DEGREES, axis=IN, about_point=np.array([x, y, 0])) mobject.rotate(deg * DEGREES, axis=IN, about_point=np.array([x, y, 0]))
def _handle_skew_transform(self, mobject, op_name, op_args): def _handle_skew_transform(self, mobject, op_name, op_args):
rad = op_args[0] * DEGREES rad = op_args[0] * DEGREES
if op_name == "skewX": if op_name == "skewX":
@ -645,7 +647,7 @@ class _PathStringParser:
while arguments: while arguments:
for rule in rules: for rule in rules:
self._rule_to_function_map[rule](arguments) self._rule_to_function_map[rule](arguments)
@property @property
def _rule_to_function_map(self): def _rule_to_function_map(self):
return { return {
@ -678,7 +680,7 @@ class _PathStringParser:
if number < 0: if number < 0:
raise InvalidPathError(f"Expected an unsigned number, got '{number}'") raise InvalidPathError(f"Expected an unsigned number, got '{number}'")
return number return number
def _get_flag(self, arg_array): def _get_flag(self, arg_array):
flag = arg_array[0] flag = arg_array[0]
if flag != 48 and flag != 49: if flag != 48 and flag != 49:

View file

@ -85,6 +85,9 @@ class Text(SVGMobject):
if self.height is None: if self.height is None:
self.scale(TEXT_MOB_SCALE_FACTOR) self.scale(TEXT_MOB_SCALE_FACTOR)
def init_colors(self, override=True):
super().init_colors(override=override)
def remove_empty_path(self, file_name): def remove_empty_path(self, file_name):
with open(file_name, 'r') as fpr: with open(file_name, 'r') as fpr:
content = fpr.read() content = fpr.read()