
Ich habe einige Probleme mit der Textausrichtung entlang des Pfads in Tikz. Ich habe eine benutzerdefinierte Form erstellt und darin Text entlang des Pfads folgendermaßen geschrieben:
\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}
Das Ergebnis ist ziemlich gut, aber es gibt kleine Probleme. Dies ist die Ausgabeohnezentrale Ausrichtung:
und das istmitzentrale Ausrichtung:
Mein Problem besteht darin, dass ich einen korrekten Zeilenumbruch (kein Zeilenumbruch in der Mitte des Wortes) und eine Ausrichtung relativ zur Mittellinie der Form und nicht des Pfads möchte.
Ich weiß, dass beim Rendern von Text entlang eines Pfads jeder Buchstabe anders umbrochen \hbox
und separat im richtigen Winkel gedreht wird.
Irgendwelche Vorschläge?
AKTUALISIEREN:
InDasDer Antwortpfad wird nur dann dekoriert, wenn der Text in den Pfad passt. Vielleicht gibt es einen ähnlichen Ansatz, um den Pfad nur mit angepasstem Text zu dekorieren und den Rest des Textes den anderen Pfaden zu überlassen?
UPDATE 2:
Ich kann Text verbergen, wenn der Text nicht in den Pfad passt, indem ich den linken Einzug neu definiere, wie in angegebenoben erwähnte Antwort:
\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
Meine Idee besteht darin, nicht nur den Textsatz zu überspringen (zum Endzustand zu wechseln), sondern auch einige Flags zu setzen, die bedeuten, dass der Text nicht gesetzt ist, sodass ich die Textlänge verringern und die Verzierung erneut aufrufen kann.
Antwort1
Meiner Idee folgend (in einem Kommentar zur Frage des OP) habe ich einige Experimente mit LuaTeX durchgeführt. Dies sind die vorläufigen Ergebnisse.
Das Latex-Beispiel
\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}
Das Ergebnis
Nach dem Kompilieren mitlualatex
Der Lua-Code
Speichern Sie es in einer Datei 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
Erläuterungen und Vorbehalte
Dies ist nur ein Proof of Concept. Der Algorithmus ist sehr naiv. Ich setze den Text in Feld 0 von TeX, aber mit parshape
den entsprechenden Längen für jede Zeile. Dann untersuche ich die resultierenden Knoten von Lua und gehe davon aus, dass jeder hbox
eine Zeile, jeder glyph
in diesem Feld ein Zeichen und jeder glue
ein Leerzeichen ist. Auf diese Weise „rekonstruiere“ ich die Zeichenfolge, die später beim Zeichnen des Tikz-Bildes für jede Zeile verwendet werden soll.
Es gibt einige Probleme, die ich nicht gelöst habe (ich weiß nicht wie):
- Ligaturen im Text unterbrechen den Algorithmus, da sie Glyphen erzeugen, die kein ASCII-Äquivalent haben. Aus diesem Grund habe ich „Fit“ statt „fit“ geschrieben, um die Ligatur „fi“ zu vermeiden.
- Aus dem gleichen Grund sind vermutlich auch keine Akzentzeichen erlaubt (nicht getestet)
- Anscheinend stört Tikz den TeX-Boxing-Mechanismus, denn wenn ich versuche, die Box in der Tikz-Umgebung zu erstellen, wird keine Box erstellt. Aus diesem Grund muss ich die Box „vorbereiten“, bevor ich Tikz öffne.
- Wahrscheinlich noch weitere Probleme, die noch nicht gefunden wurden (nicht ausreichend getestet)