为了解决我的使用预先存在的点定义 2D 画布,我偶然发现了@andrew swann 的回答通过 pgfkeys 传递 3d 坐标并尝试去适应它。
这就是 3d 坐标除了转换为 2d 坐标之外的存储方式。
% save 3d coordinates of point
\def\tdcoord #1 at (#2,#3,#4);{\pgfkeys{/tdcoords/#1/.is
family,/tdcoords/#1,x/.initial=#2,y/.initial=#3,z/.initial=#4}}
尽管一切正常,并且我能够调整画布,只需给出用附加定义的点\tdcoords
,但只有当该调用不在 foreach 循环中时它才有效。
错误消息是
- 未定义的控制序列
- 缺失数字,视为零
- \pgfmath@dimen@@ 的参数有一个额外的 }
- 段落在 \pgfmath@dimen@@ 完成之前结束
- 额外的 },或者被遗忘的 \endgroup
有人知道为什么或如何解决这个问题吗?
改编的MWE:
\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{calc}
\usepackage{tikz-3dplot}
% my adaption attempt
\makeatletter
\tikzoption{canvasP}[]{\@setPOxy#1}
\def\@setPOxy #1,#2,#3%
{\def\tikz@plane@origin{\pgfpointxyz{\GetX(#1)}{\GetY(#1)}{\GetZ(#1)}}%
\def\tikz@plane@x{\pgfpointxyz{\GetX(#2)}{\GetY(#2)}{\GetZ(#2)}}%
\def\tikz@plane@y{\pgfpointxyz{\GetX(#3)}{\GetY(#3)}{\GetZ(#3)}}%
\tikz@canvas@is@plane}
\makeatother
% save 3d coordinates of point
\def\tdcoord #1 at (#2,#3,#4);{\pgfkeys{/tdcoords/#1/.is
family,/tdcoords/#1,x/.initial=#2,y/.initial=#3,z/.initial=#4}}
% Get the 3d coordinate components of a point
\def\GetX(#1){\pgfkeysvalueof{/tdcoords/(#1)/x}}
\def\GetY(#1){\pgfkeysvalueof{/tdcoords/(#1)/y}}
\def\GetZ(#1){\pgfkeysvalueof{/tdcoords/(#1)/z}}
% Define multiple 3d points following tkz-euclide notation
\newcommand{\tkzDefdPoints}[2][]{
\foreach \ptx/\pty/\ptz/\name in {#2}{
\path [#1] (\ptx,\pty,\ptz) coordinate (\name);
\tdcoord (\name) at (\ptx,\pty,\ptz);
}
}
\tdplotsetmaincoords{70}{110}
\begin{document}
\begin{tikzpicture}[tdplot_main_coords]
\draw[->] (0,0,0) -- (5,0,0) node[right]{$x$};
\draw[->] (0,0,0) -- (0,5,0) node[above]{$y$};
\draw[->] (0,0,0) -- (0,0,5) node[below left]{$z$};
\tkzDefdPoints{2/2/2/A,2/3/2/B,2/2/3/C,
2/2/2/D,2/3/2/E,2/2/3/F}
\tdcoord (A) at (2,2,2);
\tdcoord (B) at (2,3,2);
\tdcoord (C) at (2,2,3);
\draw (A) -- (B) -- (C) -- cycle;
\begin{scope}[canvasP={A,B,C}]
\draw[red] (1,0) -- (1,1) -- (0,1);
\end{scope}
% \begin{scope}[canvasP={D,E,F}]
% \draw[blue] (0,1) -- (1,2) -- (2,1) -- (1,0);
% \end{scope}
\end{tikzpicture}
\end{document}
更新:在重命名点时,我刚刚意识到这可能与 foreach 语句无关。将坐标名称更改为非单个字母的名称会\tdcoord (AX) at (2,2,2);
产生完全相同的错误,即使在 foreach 循环之外调用它也是如此。
答案1
\@setPOxy
没有分隔符,意味着canvasP={AA,BB,CC}
将导致#3
存在C
并C
丢失到 TeX。- 您正在将
\ptx
“等”存储在值键中,而不是值中(这需要/.initial/.expanded
)。 - 循环主体
\foreach
是本地的,循环主体之后所有键分配都会丢失。
我们可以使用以下方法解决 1.
\tikzset{canvasP/.code=\@setPOxy#1\@stop}
\def\@setPOxy #1,#2,#3\@stop
{\def\tikz@plane@origin{\pgfpointxyz{\GetX(#1)}{\GetY(#1)}{\GetZ(#1)}}%
\def\tikz@plane@x{\pgfpointxyz{\GetX(#2)}{\GetY(#2)}{\GetZ(#2)}}%
\def\tikz@plane@y{\pgfpointxyz{\GetX(#3)}{\GetY(#3)}{\GetZ(#3)}}%
\tikz@canvas@is@plane}
但由于 PGFkeys 已经使用了分隔值/参数,因此我们可以在这里直接使用键:
canvasP/.code args={#1,#2,#3}{%
\def\tikz@plane@origin{\pgfpointxyz{\GetX(#1)}{\GetY(#1)}{\GetZ(#1)}}%
\def\tikz@plane@x{\pgfpointxyz{\GetX(#2)}{\GetY(#2)}{\GetZ(#2)}}%
\def\tikz@plane@y{\pgfpointxyz{\GetX(#3)}{\GetY(#3)}{\GetZ(#3)}}%
\tikz@canvas@is@plane}
当我们解决 3 时,2.问题就不再是问题了。
我们需要循环遍历您的列表,但不能将其放在组内。(我们也可以进行类似于以下的全局定义另一个答案我的原因与此类似,但那没有必要。
我们也可以使用 PGfplots,\pgfplotsinvokeforeach
但这也不是必需的,我们可以使用.list
PGFkeys 的处理程序:
def dPoints/.style 2 args={%
@def dPoints/.code args={##1/##2/##3/##4}{%
\path [#1] (##1,##2,##3) coordinate (##4);
\tdcoord (##4) at (##1,##2,##3);},
@def dPoints/.list={#2}
}
这将设置一个键@def dPoints
,该键采用四个参数,与循环/
非常相似\foreach
,但它不会将其分配给宏,也不会在将其与 一起使用时在组内执行.list
。 (在内部,.list
使用范围 (即分组)\foreach
循环,但它会在循环后执行所有内容。)
#1
的参数def dPoints
不再是可选的(但它可以为空)但因为我们有它,所以我们@def dPoints
每次想要使用它时都需要重新定义。
代码
\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{calc}
\usepackage{tikz-3dplot}
% my adaption attempt
\makeatletter
\tikzset{
canvasP/.code args={#1,#2,#3}{%
\def\tikz@plane@origin{\pgfpointxyz{\GetX(#1)}{\GetY(#1)}{\GetZ(#1)}}%
\def\tikz@plane@x{\pgfpointxyz{\GetX(#2)}{\GetY(#2)}{\GetZ(#2)}}%
\def\tikz@plane@y{\pgfpointxyz{\GetX(#3)}{\GetY(#3)}{\GetZ(#3)}}%
\tikz@canvas@is@plane},
def dPoints/.style 2 args={%
@def dPoints/.code args={##1/##2/##3/##4}{%
\path [#1] (##1,##2,##3) coordinate (##4);
\tdcoord (##4) at (##1,##2,##3);},
@def dPoints/.list={#2}
}
}
\makeatother
% save 3d coordinates of point
\def\tdcoord #1 at (#2,#3,#4);{\pgfkeys{/tdcoords/#1/.is
family,/tdcoords/#1,x/.initial=#2,y/.initial=#3,z/.initial=#4}}
% Get the 3d coordinate components of a point
\def\GetX(#1){\pgfkeysvalueof{/tdcoords/(#1)/x}}
\def\GetY(#1){\pgfkeysvalueof{/tdcoords/(#1)/y}}
\def\GetZ(#1){\pgfkeysvalueof{/tdcoords/(#1)/z}}
% Define multiple 3d points following tkz-euclide notation
\newcommand{\tkzDefdPoints}[2][]{\tikzset{def dPoints={#1}{#2}}}
\tdplotsetmaincoords{70}{110}
\begin{document}
\begin{tikzpicture}[tdplot_main_coords]
\draw[->] (0,0,0) -- (5,0,0) node[right]{$x$};
\draw[->] (0,0,0) -- (0,5,0) node[above]{$y$};
\draw[->] (0,0,0) -- (0,0,5) node[below left]{$z$};
\tkzDefdPoints{2/2/2/A,2/3/2/B,2/2/3/C,
2/2/2/D,2/3/2/E,2/2/3/F}
\tdcoord (A) at (2,2,2);
\tdcoord (B) at (2,3,2);
\tdcoord (C) at (2,2,3);
\draw (A) -- (B) -- (C) -- cycle;
\begin{scope}[canvasP={A,B,C}]
\draw[red] (1,0) -- (1,1) -- (0,1);
\end{scope}
\begin{scope}[canvasP={D,E,F}]
\draw[blue] (0,1) -- (1,2) -- (2,1) -- (1,0);
\end{scope}
\end{tikzpicture}
\end{document}