Skip to content
41 changes: 36 additions & 5 deletions manim/mobject/svg/tex_mobject.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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 = {
Expand Down Expand Up @@ -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": "",
Expand Down
94 changes: 26 additions & 68 deletions manim/mobject/svg/text_mobject.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,13 @@ class CairoText(SVGMobject):
`weird <https://github.com/3b1b/manim/issues/1067>`_. 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.')

"""

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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):
Expand Down Expand Up @@ -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.

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand Down
6 changes: 5 additions & 1 deletion manim/utils/tex_file_writing.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down