我正在绘制一个 TikZ 图形,需要几个可以在编译之间轻松更改的常数,例如主半径、比例、线数等。定义这些的首选方法是什么?
它不只是一个\draw
命令,所以我想我不能使用let
。
答案1
使用\newcommand
和\pgfmathsetmacro
:
由于您只打算更改.tex
包含的最深文件中的参数tikzpicture
,因此我将使用\newcommand*{\Name}{}%
它来设置值并使用\Name
来访问它们。
但是,如果某些参数的值是通过数学方法从另一个参数计算出来的,那么我建议使用\pgfmathsetmacro{\NewName}{}
。例如:
\newcommand*{\Diameter}{3.0}%
\pgfmathsetmacro{\Radius}{\Diameter/2}%
\pgfmathsetmacro{\Circumference}{2*pi*\Radius}%
当计算稍微复杂一些时,这将非常有用。
但是,如果您想考虑从父文档更改它们,您可以改为在文档\providecommand{}{}
中使用tikzpicture
来设置参数。这样您就可以在父文档中更改参数。这种方法的一个缺点是,存在在其他地方定义该值的风险,也不会在中触发任何错误tikzpicture
。
使用\pgfmathsetnewmacro
:
正如评论中指出的\pgfmathsetmacro
那样,使用,\def
因此如果您覆盖现有的宏名称,则不会产生错误。因此,您可以改为使用\pgfmathsetnewmacro
如下定义 -\newcommand
在调用之前,这会发出一个来检查宏是否不存在\pgfmathsetmacro
:
\newcommand*{\pgfmathsetnewmacro}[2]{%
\newcommand*{#1}{}% Error if already defined
\pgfmathsetmacro{#1}{#2}%
}%
如果您正在定义其中的值tikzpicture
并且不担心覆盖任何先前定义的值,那么您可以使用\def
和\pgfmathsetmacro
。
更新:使用问题\def
:
评论建议,如果你定义这些常量之内环境中,任何通过或tikzpicture
意外覆盖现有宏的情况都会\def
\pgfmathsetmacro
不是导致任何外部问题,tikzpicture
因为重新定义只会在tikzpicture
环境本地进行。这是不是完全准确,因为它能导致tikzpicture
环境内部出现问题,这是我经过几个小时的调试后才发现的。
随着错误的考虑到在本地范围内使用没有问题\def
,我决定更改难以阅读(如果在开头添加其他参数则难以修改)的宏,例如:
\newcommand*{\DrawXAxis}[3][]{%
\draw [ultra thick, #1] (#2,0) -- (#3,0)%
}%
像这样:
\newcommand*{\DrawXAxisReadable}[3][]{%
\def\XAxisStyle{#1}
\def\XAxisMin{#2}
\def\XAxisMax{#3}
\draw [ultra thick, \XAxisStyle] (\XAxisMin,0) -- (\XAxisMax,0)%
}%
我认为如果我在这个宏内覆盖则没有问题,\XAxisMin
因为我不需要以前设置的任何内容,并且无论如何它都会在这个宏结束时恢复。
嗯,这没问题最多案件——但是不好如果某个父宏已定义\XAxisMin
并将其作为参数传递给此宏。下面的代码说明了这一点。它按原样编译得很好,但如果你取消注释,最后一个则tikzpicture
似乎pdflatex
陷入了无限循环。
测试代码:
\documentclass{standalone}
\usepackage{tikz}
%\def\Diameter{}% Error from \newcommand if this is uncommented
%\def\Radius{}% Error from \pgfmathsetnewmacro if this is uncommented
%\def\Circumference{}% Error from \pgfmathsetnewmacro if this is uncommented
% This bascially automates a \newcommand{<name>}{} to ensure
% that a command with the given <name> does not already exist
\newcommand*{\pgfmathsetnewmacro}[2]{%
\newcommand*{#1}{}% Error if already defined
\pgfmathsetmacro{#1}{#2}%
}%
\begin{document}
\newcommand*{\Diameter}{3.0}%
\pgfmathsetnewmacro{\Radius}{\Diameter/2}%
\pgfmathsetnewmacro{\Circumference}{2*pi*\Radius}%
\newcommand{\Origin}{(0,0)}%
\begin{tikzpicture}
\draw \Origin circle (\Radius);
\end{tikzpicture}
\end{document}
代码:使用时出现\def
问题tikzpicture
:
\documentclass{article}
\usepackage{tikz}
\newcommand*{\XAxisMin}{0}%
\newcommand*{\XAxisMax}{5}%
\newcommand*{\DrawXAxis}[3][]{%
\draw [ultra thick, #1] (#2,0) -- (#3,0)%
}%
\newcommand*{\DrawXAxisReadable}[3][]{%
\def\XAxisStyle{#1}
\def\XAxisMin{#2}
\def\XAxisMax{#3}
\draw [ultra thick, \XAxisStyle] (\XAxisMin,0) -- (\XAxisMax,0)%
}%
\begin{document}
\begin{tikzpicture}
\DrawXAxis[black]{\XAxisMin}{\XAxisMax};
\end{tikzpicture}
\begin{tikzpicture}
\DrawXAxisReadable[blue]{0}{5};
\end{tikzpicture}
%%% Un comment this to see the problem
%\begin{tikzpicture}
% \DrawXAxisReadable[red]{\XAxisMin}{\XAxisMax};
%\end{tikzpicture}
\end{document}
答案2
使用\def
我通常更喜欢\def
比更短的\newcommand
。问题是, \def
不检查是否宏已经存在,所以可能被覆盖.但我\def
只使用 initions里面 {tikzpicture}
并且可能的覆盖仅存在于当前组中{tikzpicture}
\documentclass[border=1cm]{standalone}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
\def\radius{1cm}
\draw circle (\radius);
\end{tikzpicture}
\end{document}
在上面的例子中,\radius
仅在其内部定义{tikzpicture}
并且只能在其内部使用。
下一个示例显示\def
可能会产生不理想的结果
\documentclass[border=1cm]{standalone}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
\def\bfseries{1mm}
\draw [line width=\bfseries] circle (2cm);
\node {\bfseries That's the problem.};
\end{tikzpicture}
\end{document}
使用\newcommand
如果我需要一个全局变量,我更喜欢它,\newcommand
因为如果我尝试使用已经存在的宏名,它会出现错误。
\documentclass[border=1cm]{standalone}
\usepackage{tikz}
\newcommand\radius{1cm}
\begin{document}
\begin{tikzpicture}
\draw circle (\radius);
\end{tikzpicture}
\begin{tikzpicture}
\draw [red] circle (\radius);
\end{tikzpicture}
\end{document}
与“使用”中的第二个示例相同,\def
但使用\newcommand
。如果我们现在尝试使用现有命令(\bfseries
)作为 TikZ 变量,我们会收到已定义的错误消息\bfseries
。因此,用户必须决定是否重新定义它或使用其他名称,这是本例中的推荐方法。
\documentclass[border=1cm]{standalone}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
\newcommand\bfseries{1mm}
\draw [line width=\bfseries] circle (2cm);
\node {\bfseries That's the problem.};
\end{tikzpicture}
\end{document}