我有一张 TikZ 绘图(即成对的标尺),我想将其并排复制 12 次。我使用foreach
构造来帮助我完成此过程,并为标尺绘制 5 厘米、1 厘米和 1 毫米刻度。但是,当我尝试绘制它们超过第三次时,内存就用完了。
我尝试将进程外部化,但没有成功,而且我不愿意尝试增加主内存。我该如何解决这个问题?
这是MWE:
\documentclass[tikz,convert=false,12pt]{standalone}
\renewcommand*\familydefault{\sfdefault}
\usepackage[T1]{fontenc}
\usetikzlibrary{external}
\tikzexternalize
\begin{document}
%%%% Any unit not specified is multiplied by 1 mm. This allows some fancy scaling.
\begin{tikzpicture}[x=1mm,line cap=rect]
%%%% We need 12 rulers, mirrored, for a grand total of 24 rulers. Each pair of
%%%% rulers will be offset 10 cm from the previous pair.
\foreach \i in {0,...,2}{ %%%% Ideally, this would be 11 and not 2.
\tikzset{xshift/.expanded=\i*100mm}
%%%% Draw the red millimeter tick marks.
\foreach \y in {0.1,0.3,...,69.9}
\draw [color=red, line width=0.15mm] (10mm,\y) -- (0mm,\y)
node[color=red] {};
%%%% Draw the black millimeter tick marks
\foreach \y in {0,0.2,...,69.8}
\draw [color=black, line width=0.15mm] (10mm,\y) -- (0mm,\y)
node[color=black] {};
%%%% Draw the red minor(centimeter) tick marks with the red labels.
\foreach \y in {1,3,...,69}
\draw [color=red, line width=1mm] (20mm,\y) -- (0mm,\y)
node[color=red, anchor=east] {\pgfmathprint{int(\y)}};
%%%% Draw the black minor (centimeter) tick marks with the black labels.
\foreach \y in {0,2,...,68}
\draw [color=black, line width=1mm] (20mm,\y) -- (0mm,\y)
node[color=black, anchor=east] { \pgfmathprint{int(\y)}};
%%%% Draw the black major (5-cm) tick marks with the black labels. This paints over
%%%% the minor tick marks in the same place.
\foreach \y in {0,10,...,70}
\draw [color=black,line width=2mm] (30mm,\y) -- (0mm,\y)
node[fill=white,anchor=east] {\Huge \textbf{{\pgfmathprint{int(\y)}}}};
%%%% Draw the red major (5-cm) tick marks with the red labels. This paints over
%%%% the minor tick marks in the same place.
\foreach \y in {5,15,...,65}
\draw [color=red, line width=2mm] (30mm,\y) -- (0mm,\y)
node[fill=white,anchor=east] {\Huge \textbf{\pgfmathprint{int(\y)}}};
%%%% Draw the vertical line that ties it all together.
\draw [line width=2mm](0mm, 0mm) -- coordinate (y axis mid) (0mm,700mm);
%%%% ------------------------------ REVERSED RULERS
%%%% Draw the red millimeter tick marks. Reversed.
\foreach \y in {0.1,0.3,...,69.9}
\draw [color=red, line width=0.15mm] (60mm,\y) -- (70mm,\y)
node[color=red] {};
%%%% Draw the black millimeter tick marks. Reversed
\foreach \y in {0,0.2,...,69.8}
\draw [color=black, line width=0.15mm] (60mm,\y) -- (70mm,\y)
node[color=black] {};
%%%% Draw the red minor tick marks with the red labels. Reversed
\foreach \y in {1,3,...,69}
\draw [color=red, line width=1mm] (50mm,\y) -- (70mm,\y)
node[color=red, anchor=west] {\pgfmathprint{int(\y)}};
%%%% Draw the black minor tick marks with the black labels. Reversed
\foreach \y in {0,2,...,68}
\draw [color=black, line width=1mm] (50mm,\y) -- (70mm,\y)
node[color=black, anchor=west] { \pgfmathprint{int(\y)}};
%%%% Draw the black major tick marks with the black labels. This paints over
%%%% the minor tick marks in the same place. Reversed
\foreach \y in {0,10,...,70}
\draw [color=black,line width=2mm] (40mm,\y) -- (70mm,\y)
node[fill=white,anchor=west] {\Huge \textbf{{\pgfmathprint{int(\y)}}}};
%%%% Draw the red major tick marks with the red labels. This paints over
%%%% the minor tick marks in the same place. Reversed
\foreach \y in {5,15,...,65}
\draw [color=red, line width=2mm] (40mm,\y) -- (70mm,\y)
node[fill=white,anchor=west] {\Huge \textbf{\pgfmathprint{int(\y)}}};
%%%% Draw the vertical line that ties it all together, reversed
\draw [line width=2mm](70mm, 0cm) -- coordinate (y axis mid) (70mm,700mm);
% %%%% Draw crop marks.
% \draw [very thin, color=black, loosely dashed](-1, 0cm) -- coordinate
% (y axis mid) (-1cm,71cm);
}
\end{tikzpicture}
\end{document}
%%% Local Variables:
%%% mode: latex
%%% LaTeX-command: "latex -shell-escape"
%%% TeX-master: t
%%% End:
答案1
结果
想法
这个想法是使用 lua 编写所有这些嵌套循环,然后从这些循环生成 tex (tikz) 代码来绘制各个标记。因此,TikZ 最终“看到”的是循环的结果,即一长串简单的线条绘制命令。这样,TeX 内存就不会堵塞。
但是,lua 循环中生成的小标记数量非常多,整个过程需要花费大量时间来编译(在我的机器上,每条标尺需要 12 秒,总共需要 2 分 30 秒)。也许可以优化一下,如果不是将生成的每行都发送给 TeX,而是将它们累积在一个列表中,然后发送整个列表。我必须尝试一下,但我猜真正的瓶颈是 TikZ 解析所有这些行。
代码
它分为两个文件,一个用于 lua 代码,另一个用于使用它的主 TeX 文档。编译:
$ lualatex main.tex
过一会儿,您将获得一个pdf
可以打印或包含在其他文档中的文件(通过\includegraphics
)。
主文本
乳胶代码现在已很少。
\documentclass[tikz,convert=false,12pt]{standalone}
\renewcommand*\familydefault{\sfdefault}
\usepackage[T1]{fontenc}
\directlua{dofile("drawrule.lua")}
\def\DrawAllRules{\directlua{DrawAllRules()}}
\begin{document}
%%%% Any unit not specified is multiplied by 1 mm. This allows some fancy scaling.
\begin{tikzpicture}[x=1mm,line cap=rect]
\DrawAllRules
\end{tikzpicture}
\end{document}
绘制规则
我尝试让 lua 代码尽可能接近您的原始 tex 代码。我使用了一些字符串来保存在其他地方重复的 tikz 命令,但使用类似“printf”的占位符进行参数化
function DrawRule()
t = {}
mmcmd = "\\draw [color=%s, line width=0.15mm] (10mm,%f) -- (0mm,%f) node[color=%s] {};\n"
cmcmd = "\\draw [color=%s, line width=1mm] (20mm,%f) -- (0mm,%f) node[color=%s,anchor=east] {%d};\n"
cm5cmd= "\\draw [color=%s, line width=2mm] (30mm,%f) -- (0mm,%f) node[fill=white, anchor=east] {\\Huge\\textbf{%d}};\n"
-- Draw the red millimeter tick marks.
for y = 0.1, 69.9, 0.2 do -- first, last, step
tex.print(string.format(mmcmd, "red", y, y, "red"))
end
-- Draw the black millimeter tick marks
for y = 0, 69.8, 0.2 do -- first, last, step
tex.print(string.format(mmcmd, "black", y, y, "black"))
end
-- Draw the red minor(centimeter) tick marks with the red labels.
for y = 1, 69, 2 do -- first, last, step
tex.print(string.format(cmcmd, "red", y, y, "red", y)) end
-- Draw the black minor (centimeter) tick marks with the black labels. for y = 0, 68, 2 do -- first, last, step
tex.print(string.format(cmcmd, "black", y, y, "black", y))
end
-- Draw the black major (5-cm) tick marks with the black labels. This paints over
-- the minor tick marks in the same place.
for y = 0,70,10 do
tex.print(string.format(cm5cmd, "black", y, y, y))
end
-- Draw the red major (5-cm) tick marks with the red labels. This paints over
-- the minor tick marks in the same place.
for y = 5, 65, 10 do
tex.print(string.format(cm5cmd, "red", y, y, y))
end
-- Draw the vertical line that ties it all together.
tex.print("\\draw [line width=2mm](0mm, 0mm) -- coordinate (y axis mid) (0mm,700mm);\n")
------------------------------ REVERSED RULERS
mmcmd = "\\draw [color=%s, line width=0.15mm] (60mm,%f) -- (70mm,%f) node[color=%s] {};\n"
cmcmd = "\\draw [color=%s, line width=1mm] (50mm,%f) -- (70mm,%f) node[color=%s,anchor=west] {%d};\n"
cm5cmd= "\\draw [color=%s, line width=2mm] (40mm,%f) -- (70mm,%f) node[fill=white, anchor=west] {\\Huge\\textbf{%d}};\n"
-- Draw the red millimeter tick marks. Reversed.
for y = 0.1, 69.9, 0.2 do -- first, last, step
tex.print(string.format(mmcmd, "red", y, y, "red"))
end
-- Draw the black millimeter tick marks. Reversed.
for y = 0, 69.8, 0.2 do -- first, last, step
tex.print(string.format(mmcmd, "black", y, y, "black")) end
-- Draw the red minor(centimeter) tick marks with the red labels. Reversed. for y = 1, 69, 2 do -- first, last, step
tex.print(string.format(cmcmd, "red", y, y, "red", y))
end
-- Draw the black minor (centimeter) tick marks with the black labels. Reversed.
for y = 0, 68, 2 do -- first, last, step
tex.print(string.format(cmcmd, "black", y, y, "black", y))
end
-- Draw the black major (5-cm) tick marks with the black labels. This paints over
-- the minor tick marks in the same place. Reversed.
for y = 0,70,10 do
tex.print(string.format(cm5cmd, "black", y, y, y))
end
-- Draw the red major (5-cm) tick marks with the red labels. This paints over
-- the minor tick marks in the same place. Reversed.
for y = 5, 65, 10 do
tex.print(string.format(cm5cmd, "red", y, y, y))
end
-- Draw the vertical line that ties it all together, reversed
tex.print("\\draw [line width=2mm](70mm, 0cm) -- coordinate (y axis mid) (70mm,700mm);\n")
-- %%%% Draw crop marks.
-- \draw [very thin, color=black, loosely dashed](-1, 0cm) -- coordinate
-- (y axis mid) (-1cm,71cm);
end
function DrawAllRules() for i=0,11 do
tex.print(string.format("\\tikzset{xshift/.expanded=100mm}"))
DrawRule() end
end