
Tengo algunos problemas con la alineación del texto a lo largo del camino en tikz. Hice una forma personalizada y escribí texto a lo largo del camino dentro de ella de la siguiente manera:
\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}
El resultado es bastante bueno, pero hay pequeños problemas. Esta es la salidasinalineación central:
y esto esconalineación central:
Mi problema es que quiero un salto de línea correcto (no romper líneas en el medio de la palabra) y una alineación relativa a la línea central de la forma, no al camino.
Sé que al representar texto a lo largo del camino, cada letra se ajusta de manera diferente \hbox
y gira en el grado correcto por separado.
¿Alguna sugerencia?
ACTUALIZAR:
EnesteLa ruta de respuesta se decora solo en caso de que el texto se ajuste a la ruta. ¿Puede haber un enfoque similar para decorar el camino solo con texto ajustado y dejar el resto del texto en los otros caminos?
ACTUALIZACIÓN 2:
Puedo ocultar texto si el texto no se ajusta a la ruta redefiniendo el estado de sangría izquierda como se indica enrespuesta mencionada arriba:
\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
Mi idea es no solo omitir el texto tipográfico (cambiar al estado final), sino también establecer alguna marca que signifique que el texto no está tipográfico, para poder disminuir la longitud del texto y llamar a la decoración nuevamente.
Respuesta1
Siguiendo mi idea (en un comentario a la pregunta del OP), hice algunos experimentos con LuaTeX. Estos son los resultados preliminares.
El ejemplo del látex
\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}
El resultado
Después de compilar conlualatex
El código lua
Guárdalo en un archivo 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
Explicaciones y advertencias
Esto es sólo una prueba de concepto. El algoritmo es muy ingenuo. Escribí el texto en el cuadro 0 de TeX, pero con a parshape
con las longitudes adecuadas para cada línea. Luego examino los nodos resultantes de lua, asumiendo que cada uno hbox
es una línea, cada uno glyph
dentro de ese cuadro es un carácter y cada uno glue
es un espacio. De esta manera "reconstruyo" la cadena que se usará para cada línea más adelante, al dibujar la imagen tikz.
Hay algunos problemas que no resolví (no sé cómo):
- Las ligaduras en el texto rompen el algoritmo porque producen glifos que no tienen equivalente ascii. Por eso escribí "Fit" en lugar de "fit", para evitar la ligadura "fi".
- Por la misma razón, probablemente no se permitan caracteres acentuados (no probado)
- Aparentemente, tikz interfiere con el mecanismo de boxeo TeX, porque si intento crear la caja dentro del entorno tikz, no se produce ninguna caja. Por eso tengo que "preparar" la caja antes de entrar a tikz.
- Probablemente aún no se han encontrado más problemas (no se han probado mucho)