如何编写返回路径或坐标的宏?
以下是一个例子:
\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 的tkz
bundle 实际上定义了我可能需要的平面几何的大多数函数,但这个问题的重点是更多地了解如何编写 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 构建路径时才有效。
举个例子,你可以看看calligraphy
TeX-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}