diff --git a/manim/mobject/svg/tex_mobject.py b/manim/mobject/svg/tex_mobject.py index 8f6230214f..30965f0bd5 100644 --- a/manim/mobject/svg/tex_mobject.py +++ b/manim/mobject/svg/tex_mobject.py @@ -38,6 +38,16 @@ class TexSymbol(VMobjectFromSVGPathstring): class SingleStringMathTex(SVGMobject): + """Elementary building block for rendering text with LaTeX. + + Tests + ----- + Check that creating a :class:`~.SingleStringMathTex` object works:: + + >>> SingleStringMathTex('Test') + SingleStringMathTex('Test') + """ + CONFIG = { "stroke_width": 0, "fill_opacity": 1.0, @@ -68,6 +78,9 @@ def __init__(self, tex_string, **kwargs): if self.organize_left_to_right: self.organize_submobjects_left_to_right() + def __repr__(self): + return f"{type(self).__name__}({repr(self.tex_string)})" + def get_modified_expression(self, tex_string): result = self.alignment + " " + tex_string result = result.strip() @@ -152,19 +165,25 @@ def organize_submobjects_left_to_right(self): class MathTex(SingleStringMathTex): - """ - A class for displaying mathematical formulas with Latex syntax. - + """A string compiled with LaTeX in math mode. Examples -------- - .. manim:: Formula1 + .. manim:: Formula :save_last_frame: - class Formula1(Scene): + class Formula(Scene): def construct(self): t = MathTex(r"\int_a^b f'(x) dx = f(b)- f(a)") self.add(t) + + Tests + ----- + Check that creating a :class:`~.MathTex` works:: + + >>> MathTex('a^2 + b^2 = c^2') + MathTex('a^2 + b^2 = c^2') + """ CONFIG = { @@ -276,6 +295,18 @@ def sort_alphabetically(self): class Tex(MathTex): + r"""A string compiled with LaTeX in normal mode. + + Tests + ----- + + Check whether writing a LaTeX string works:: + + >>> Tex('The horse does not eat cucumber salad.') + Tex('The horse does not eat cucumber salad.') + + """ + CONFIG = { "alignment": "\\centering", "arg_separator": "", diff --git a/manim/mobject/svg/text_mobject.py b/manim/mobject/svg/text_mobject.py index da5fd26f55..906be3d176 100644 --- a/manim/mobject/svg/text_mobject.py +++ b/manim/mobject/svg/text_mobject.py @@ -83,8 +83,13 @@ class CairoText(SVGMobject): `weird `_. Consider using :meth:`remove_invisible_chars` to resolve this issue. + Tests + ----- + Check whether writing text works:: + >>> Text('The horse does not eat cucumber salad.') + Text('The horse does not eat cucumber salad.') """ @@ -158,6 +163,9 @@ def __init__(self, text, **config): if self.height is None and self.width is None: self.scale(TEXT_MOB_SCALE_FACTOR) + def __repr__(self): + return f"Text({repr(self.original_text)})" + def gen_chars(self): chars = VGroup() submobjects_char_index = 0 @@ -299,9 +307,13 @@ def text2svg(self): line_spacing = self.line_spacing * 10 if self.font == "": - if NOT_SETTING_FONT_MSG != "": - print(NOT_SETTING_FONT_MSG) + if NOT_SETTING_FONT_MSG: + logger.warning(NOT_SETTING_FONT_MSG) + dir_name = file_writer_config["text_dir"] + if not os.path.exists(dir_name): + os.makedirs(dir_name) + hash_name = self.text2hash() file_name = os.path.join(dir_name, hash_name) + ".svg" if os.path.exists(file_name): @@ -333,71 +345,6 @@ def text2svg(self): return file_name -# Following class is just a Little implementation of upcomming feautures. Ignore it for now. -class TextWithBackground(CairoText): - CONFIG = { - "background_color": BLACK, - } - - def __init__(self, text, **config): - Text.__init__(self, text, **config) - # self.text_backgrounds = self.gen_text_backgrounds(text) - - def gen_text_backgrounds(self, text): - text_with_visible_chars = text.replace(" ", "").replace("\t", "") - text_list = text_with_visible_chars.split("\n") - text_backgrounds = VGroup() - start_i = 0 - for line_no in range(text_list.__len__()): - rect_counts = len(text_list[line_no]) - text_backgrounds.add(*self[start_i:rect_counts]) - start_i += 2 * rect_counts - text_backgrounds.set_color(self.background_color) - - return text_backgrounds - - def text2svg1(self): - # anti-aliasing - size = self.size * 10 - line_spacing = self.line_spacing * 10 - - if self.font == "": - if NOT_SETTING_FONT_MSG != "": - logger.warning(NOT_SETTING_FONT_MSG) - dir_name = consts.TEXT_DIR - hash_name = self.text2hash() - file_name = os.path.join(dir_name, hash_name) + ".svg" - # if os.path.exists(file_name): - # return file_name - - surface = cairo.SVGSurface(file_name, 600, 400) - context = cairo.Context(surface) - context.set_font_size(size) - context.move_to(START_X, START_Y) - - settings = self.text2settings() - offset_x = 0 - last_line_num = 0 - for setting in settings: - font = setting.font - slant = self.str2slant(setting.slant) - weight = self.str2weight(setting.weight) - text = self.text[setting.start : setting.end].replace("\n", " ") - context.select_font_face(font, slant, weight) - if setting.line_num != last_line_num: - offset_x = 0 - last_line_num = setting.line_num - tempx = START_X + offset_x - tempy = START_Y + line_spacing * setting.line_num - char_offset_x = 0 - char_height = tempy - size / 2 - (line_spacing - size) - context.move_to(tempx, tempy) - context.show_text(text) - offset_x += context.text_extents(text)[4] - surface.finish() - return file_name - - class Paragraph(VGroup): r"""Display a paragraph of text. @@ -634,6 +581,14 @@ def construct(self): self.play(Write(morning)) self.wait(2) + Tests + ----- + + Check that the creation of :class:`~.PangoText` works:: + + >>> PangoText('The horse does not eat cucumber salad.') + Text('The horse does not eat cucumber salad.') + .. WARNING:: Using a :class:`.Transform` on text with leading whitespace can look @@ -711,6 +666,9 @@ def __init__(self, text: str, **config): # pylint: disable=redefined-outer-name if self.height is None and self.width is None: self.scale(TEXT_MOB_SCALE_FACTOR) + def __repr__(self): + return f"Text({repr(self.original_text)})" + def remove_last_M(self, file_name: str): # pylint: disable=invalid-name """Internally used. Use to format the rendered SVG files.""" with open(file_name, "r") as fpr: @@ -922,7 +880,7 @@ class Text(CairoText): Text objects behave like a :class:`.VGroup`-like iterable of all characters in the given text. In particular, slicing is possible. - Examples + Examples -------- .. manim:: Example1Text :save_last_frame: diff --git a/manim/utils/tex_file_writing.py b/manim/utils/tex_file_writing.py index 51298b1acd..d36b17dd8b 100644 --- a/manim/utils/tex_file_writing.py +++ b/manim/utils/tex_file_writing.py @@ -37,7 +37,11 @@ def generate_tex_file(expression, tex_template, source_type): elif source_type == "tex": output = tex_template.get_text_for_tex_mode(expression) - result = os.path.join(file_writer_config["tex_dir"], tex_hash(output)) + ".tex" + tex_dir = file_writer_config["tex_dir"] + if not os.path.exists(tex_dir): + os.makedirs(tex_dir) + + result = os.path.join(tex_dir, tex_hash(output)) + ".tex" if not os.path.exists(result): logger.info('Writing "%s" to %s' % ("".join(expression), result)) with open(result, "w", encoding="utf-8") as outfile: