TikZ 编程

TikZ 编程

如何编写返回路径或坐标的宏?

以下是一个例子:

\documentclass[border=2em]{standalone}
\usepackage{tikz}
\usetikzlibrary{calc}
% \circleByPoint{centre}{point} draws a circle with centre at centre through point
\newcommand\circleByPoint[2]{
  \draw let \p1 = (#1),\p2 = (#2) in
  \pgfextra{\pgfmathveclen{\x1-\x2}{\y1-\y2}}
  (#1) circle (\pgfmathresult pt);
}
\begin{document}
\begin{tikzpicture}
\node at (0,0) (a) {};
\node at (1,0) (b) {};
\node at (0,3) (c) {};
\circleByPoint{a}{b}
\circleByPoint{b}{c}
\circleByPoint{c}{a}
\end{tikzpicture}
\end{document}

这里我定义了一个绘制圆的宏。同样,我可以定义一个绘制线段垂直平分线的宏(给定两个点)。问题是,如果我希望宏的结果是路径而不是让它只绘制路径?许多程序语言都有类似的东西,return它允许你指定函数返回什么。我不知道如何让它在 TikZ 中工作......

例如,以下 MWE 无法正确编译(事实上,它挂起了):

\documentclass[border=2em]{standalone}
\usepackage{tikz}
\usetikzlibrary{calc}
\newcommand\apath[2]{
  \path (#1) -- (#2);
}
\begin{document}
\begin{tikzpicture}
\node at (0,0) (a) {};
\node at (1,0) (b) {};
\node at (0,3) (c) {};
\node at (intersection of \apath{a}{b} and \apath{a}{c}) {x};
\end{tikzpicture}
\end{document}

所以我的问题是,如何为 TikZ 编写这样的辅助函数?

(我知道 Altermundus 的tkzbundle 实际上定义了我可能需要的平面几何的大多数函数,但这个问题的重点是更多地了解如何编写 TikZ 代码。)

答案1

那样的话,疯狂就来了!

我想说我们应该为这类事情设立一个专门的 TikZ 聊天室,因为通常很难提出一个精确的问题。此外,学习这一点的最佳地点是 PGF2.10 手册,因为其中包含从 TikZ 到 PGF 再到实际输出的过程的一些详细信息。

但无论如何,这里要回答你的具体问题。简而言之,TikZ 代码调用 PGF 代码来绘制所谓的软路径。softpath 是一个宏,包含有关如何绘制路径的非常基本的指令。在构建 softpath 时,所有坐标都已转换为帆布坐标,所有复杂的路径都简化为直线、贝塞尔曲线和矩形,所有花哨的东西,如圆角都已完成。箭头没有,也没有其他花招。软路径的关键在于它们 1) 采用标准格式,2) 可操作。因此,当您希望宏返回路径时,最好的做法是让它返回软路径。

有一个 TikZ 选项可以执行此操作:save path=\pathname。如果您将其放在路径上,它将保存在宏中\pathname。然后您可以随意摆弄它,直到您准备好将其“烘焙”到正确的路径中。为此,您需要\pgfsyssoftpath@setcurrentpath{\pathname}\pgfsyssoftpath@flushcurrentpath然后\pgfusepath{stroke}(或其他)。如果您想先添加东西,然后发出命令\pgfsyssoftpath@setcurrentpath{\pathname},执行新命令,它们将被添加到当前路径(注意:不是\pathname,如果您想存储它,则需要再次保存它)。如果您对软路径感到困惑,则需要使用较低级别的方法来保存路径:\pgfsyssoftpath@getcurrentpath{\pathname}因为 tikz 选项仅在由 TikZ 构建路径时才有效。

举个例子,你可以看看calligraphyTeX-SX 元包中的包。“笔”是软路径,所以我有一些代码可以让你定义笔并保存生成的软路径(并且这样做不会影响边界框)。然后有一些相当混乱的软路径操作,它采用笔路径并通过笔路径“加粗”它。

然而,这仍然不会在你的 MWE 中起作用,因为(正如 Caramdir 刚刚指出的那样)交集语法的输入不是实际路径而是路径的名称。要做到这一点,您必须查看交叉点的代码,以准确确定它将接受什么输入(Caramdir 已经为您完成了!)。

答案2

坐标系中的参数intersection不会被解析为路径。因此,您必须从宏中返回正确的语法(包括正确数量的空格,即无):

\documentclass[border=2em]{standalone}
\usepackage{tikz}
\usetikzlibrary{calc}
\newcommand\apath[2]{
  #1--#2% no additional space at end
}
\begin{document}
\begin{tikzpicture}
\node at (0,0) (a) {};
\node at (1,0) (b) {};
\node at (0,3) (c) {};
\node at (intersection of \apath{a}{b} and \apath{a}{c}) {x};
\end{tikzpicture}
\end{document}

请注意,这种语法似乎在 TikZ v2.10 中已被弃用,取而代之的是更灵活(但更冗长)的name path/name intersections语法。

答案3

嗯,您的 MWE 中还有别的问题,交叉点的语法似乎在 2.10 中不起作用,我找不到任何相关文档。(对于任意交叉点,语法要复杂得多。)

但你想做的事情其实很简单(我想;预览时 Andrew Stacey 的回答让我有点困惑)。要记住的是,tikz 嵌入在宏语言中,因此问题不在于函数返回什么,而在于它扩展为什么文本。创建扩展到 tikz 路径表达式部分的宏很容易。这是一个简单的例子,与你想要的没有交集的东西类似。

\documentclass{article}
\usepackage{tikz}

\begin{document}

\newcommand\apath[2]{(#1) -- (#2)}

\begin{tikzpicture}
\node at (0,0) (a) {a};
\node at (0,1) (b) {b};
\node at (1,1) (c) {c};
\draw \apath{a}{b} \apath{b}{c} \apath{a}{c};
\end{tikzpicture}

\end{document}

此版本\apath可以出现在路径描述可以出现的任何地方。

要记住的一点是,有很多事情你不能只在子路径中做,所以有时对于足够复杂的宏,要获得这种没有终止路径作为部分的宏会变得很棘手,然后你在包含绘制中传递的任何选项都不会应用于宏的整个结果,并且会变得一团糟。例如,如果我没记错的话,填充和装饰适用于整个路径和任何子路径,如果它们在路径表达式中的任何位置。但在这些情况下仍然可以让宏在没有命令的情况下开始\draw并且在没有命令的情况下结束;,因此你可以表面上将它嵌入到路径中,只是路径选项是一个问题。

答案4

有可能,但我不喜欢这个代码

\documentclass[border=2em]{standalone} 
\usepackage{tikz}
\usetikzlibrary{intersections}
\newcommand\apath[3]{
  \path[name path=#3] (#1) -- (#2);
}
\begin{document}
\begin{tikzpicture}
  \node (a) at (0,3){}; 
  \node (b) at (4,0){}; 
  \node (c) at (1,-2){};
  \node (d) at (4,3){};
  \draw (a)--(b);
  \draw (d)--(c);
 \draw 
   \pgfextra{\apath{a}{b}{pathone}
             \apath{d}{c}{pathtwo}}
 [ name intersections={of=pathone and pathtwo},red] (intersection-1) circle (2pt) ;  
\end{tikzpicture}
\end{document}

相关内容