Пример с латексом

Пример с латексом

У меня возникли проблемы с выравниванием текста вдоль пути в tikz. Я создал пользовательскую форму и написал текст вдоль пути внутри нее следующим образом:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{decorations.text}
\begin{document}
\begin{tikzpicture}

% shape
\draw (70:3) arc (70:110:3)
   -- (110:5)  arc (110:70:5)
   -- cycle;

\path[
  postaction={
    decorate,
    decoration={
      text along path,
      text align = center,
      text={Gershon Daly Bonifacy Yaw}
    }
  }
]
(105:4.5) arc (105:75:4.5)
(105:4.0) arc (105:75:4.0)
(105:3.5) arc (105:75:3.5);

\end{tikzpicture}
\end{document}

Результат довольно хороший, но есть небольшие проблемы. Это выводбезЦентральное выравнивание:

без выравнивания

а этосЦентральное выравнивание:

с выравниванием

Моя проблема в том, что мне нужен правильный разрыв строки (не разрывать строки в середине слова) и выравнивание относительно центральной линии фигуры, а не контура.

Я знаю, что при отображении текста по траектории каждая буква переносится по-разному \hboxи поворачивается на нужный градус по отдельности.

Какие-либо предложения?

ОБНОВЛЯТЬ:

ВэтотПуть ответа декорируется только в том случае, если текст вписывается в путь. Может быть, есть похожий подход, чтобы декорировать путь только вписанным текстом и оставить остальной текст для других путей?

ОБНОВЛЕНИЕ 2:

Я могу скрыть текст, если он не вписывается в контур, переопределив состояние левого отступа, как указано вупомянутый ответ выше:

\makeatletter
  \pgfkeys{
    /pgf/decoration/omit long text/.code={%
      \expandafter\def\csname pgf@decorate@@text along path@left indent@options\expandafter\expandafter\expandafter\endcsname\expandafter\expandafter\expandafter{\csname pgf@decorate@@text along path@left indent@options\endcsname,switch if less than=\pgf@lib@dec@text@width to final}%
    },
  }
\makeatother

Моя идея состоит в том, чтобы не только пропустить набор текста (перейти в конечное состояние), но и установить какой-то флаг, который будет означать, что текст не набран, чтобы я мог уменьшить длину текста и снова вызвать оформление.

решение1

Следуя своей идее (в комментарии к вопросу ОП), я провел несколько экспериментов с LuaTeX. Вот предварительные результаты.

Пример с латексом

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{decorations.text}
\directlua{dofile("testing.lua")}
\begin{document}
\sffamily

% Before entering tikzpicture
\directlua{PrepareText({{105,75,4.5}, {105,75,4}, {105,75,3.5}}, 
           "Gershon Daly Bonifacy Yaw")}
\begin{tikzpicture}
\draw (70:3) arc (70:110:3)
   -- (110:5)  arc (110:70:5)
   -- cycle;
\directlua{TypeInArcs()}
\end{tikzpicture}
%
% A second example
\directlua{PrepareText({{105,75,4.5}, {105,75,4}, {105,75,3.5}}, 
"This is another longer test, which does not Fit")}
\begin{tikzpicture}
\draw (70:3) arc (70:110:3)
   -- (110:5)  arc (110:70:5)
   -- cycle;
\directlua{TypeInArcs()}
\end{tikzpicture}
%
% Third example
\directlua{PrepareText({{105,75,4.5}, {105,75,4}, {105,75,3.5}, {105,75,3}}, 
"This is another longer test, which now does Fit")}
\begin{tikzpicture}
\draw (70:2.5) arc (70:110:2.5)
   -- (110:5)  arc (110:70:5)
   -- cycle;
\directlua{TypeInArcs()}
\end{tikzpicture}

\end{document}

Результат

После компиляции с помощьюlualatex

Результат

Код lua

Сохраните его в файле testing.lua:

function GetLinesFromBox()
        local lines,i,j,l,d,list,words
        lines = {}; j = 1;
        d=node.types();
        list = tex.box[0].head
        node.unprotect_glyphs(list)
        for l in node.traverse(list) do
            if (d[l.id]=="hlist") then
                words = {}; i = 1
                for l in node.traverse(l.head) do
                    if (d[l.id]=="glyph") then
                        words[i] = string.char(l.char)
                        i=i+1
                    end
                    if (d[l.id]=="glue") then
                        words[i] = " "
                        i=i+1
                    end
                end
                lines[j] = table.concat(words,"")
                j=j+1
            end
        end
        return lines
end

function ComputeLengthArc(start_, end_, radius)
    return (radius*(math.abs(start_-end_)*2*math.pi/360))
end

global_arcs = {}
global_text = ""

function PrepareText(arcs, text)
    local j,l
    global_arcs = arcs
    global_text = text
    tex.print("\\setbox0=\\vbox{\\centering\\parshape ", #arcs)
    for j=1,#arcs do
        l = ComputeLengthArc(arcs[j][1], arcs[j][2], arcs[j][3] )
        tex.print("0cm "..l.."cm ")
    end
    tex.print("\\noindent ".. text .. "}")
end

function TypeInArcs()
    local lines,j
    lines = GetLinesFromBox()
    for j=1,#global_arcs do
        if lines[j]~=nil then
            tex.sprint("\\path[ postaction = { decorate, decoration = {")
            tex.sprint("  text along path,")
            tex.sprint("  text align = center,")
            tex.sprint("  text={"..lines[j].."}")
            tex.sprint("} } ]")
            tex.sprint("("..global_arcs[j][1]..":"..global_arcs[j][3]..
                  ") arc ("..global_arcs[j][1]..":"..global_arcs[j][2]..":"..global_arcs[j][3]..");")
        end
    end
end

Пояснения и предостережения

Это всего лишь доказательство концепции. Алгоритм очень наивен. Я набираю текст в поле TeX 0, но с parshapeсоответствующей длиной для каждой строки. Затем я проверяю полученные узлы из lua, предполагая, что каждый из них hboxявляется строкой, каждый glyphвнутри этого поля является символом, и каждый glueявляется пробелом. Таким образом я «реконструирую» строку, которая будет использоваться для каждой строки позже, при рисовании изображения tikz.

Есть несколько проблем, которые я не решил (не знаю как):

  1. Лигатуры в тексте нарушают алгоритм, поскольку создают глифы, не имеющие эквивалента в ascii. Вот почему я написал "Fit" вместо "fit", чтобы избежать лигатуры "fi".
  2. По этой же причине, вероятно, не допускаются символы с ударением (не тестировалось)
  3. Видимо, tikz вмешивается в механизм упаковки TeX, потому что если я пытаюсь создать коробку внутри среды tikz, коробка не создается. Вот почему мне приходится "подготавливать" коробку перед входом в tikz.
  4. Вероятно, пока не обнаружено больше проблем (мало проверено)

Связанный контент