我在 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 图片时用于每行的字符串。
有一些问题我没有解决(我不知道如何解决):
- 文本中的连字符会破坏算法,因为会产生没有 ASCII 等效字符的字形。这就是为什么我写“Fit”而不是“fit”,以避免“fi”连字符。
- 出于同样的原因,可能不允许使用重音字符(未经测试)
- 显然 tikz 干扰了 TeX 装箱机制,因为如果我尝试在 tikz 环境中创建盒子,则不会生成任何盒子。这就是为什么我必须在进入 tikz 之前“准备”盒子。
- 可能还有更多问题尚未发现(没有经过太多测试)