我正在使用 3dplot 进行 3D 绘图。现在我想定义自己的环境,称为姿势,该环境应该在 tikzpicture 环境中使用。它应该根据 x、y、z、roll、pitch 和 yaw 执行坐标系变换,这些变换通过 pgfkeys 传递给我的姿势环境。
以下是代码:
\documentclass{article}
\usepackage{tikz}
\usepackage{tikz-3dplot}
\usetikzlibrary{3d}
% fix wrong implementation of xy canvas
\makeatletter
\tikzoption{canvas is xy plane at z}[]{%
\def\tikz@plane@origin{\pgfpointxyz{0}{0}{#1}}%
\def\tikz@plane@x{\pgfpointxyz{1}{0}{#1}}%
\def\tikz@plane@y{\pgfpointxyz{0}{1}{#1}}%
\tikz@canvas@is@plane
}
\makeatother
\pgfkeys{%
/poseenv/.is family, /poseenv,%
% set the defaut values
default/.style = {%
x = 0,%
y = 0,%
z = 0,%
roll = 0,%
pitch = 0,%
yaw = 0%
},%
x/.estore in = \poseenvx,%
y/.estore in = \poseenvy,%
z/.estore in = \poseenvz,%
roll/.estore in = \poseenvroll,%
pitch/.estore in = \poseenvpitch,%
yaw/.estore in = \poseenvyaw,%
origin/.code n args={1}{%
#1% ### MODIFY CODE HERE ###
}%
}%
\newenvironment{pose}[1][]%
{%
% parse arguments
\pgfkeys{/poseenv, default, #1}%
% modify 3dplot's rotated coords according to \poseenv{x,y,z,roll,pitch,yaw}
\coordinate (origin) at (\poseenvx,\poseenvy,\poseenvz);
\tdplotsetrotatedcoordsorigin{(origin)}
% todo: do rotation
% begin the scope
\begin{scope}[tdplot_rotated_coords,transform shape]
}%
{%
% end the scope
\end{scope}
}%
\begin{document}
\tdplotsetmaincoords{80}{45}
\begin{tikzpicture}[tdplot_main_coords]
% draw a coordinate system in black at the origin
\draw[->] (0,0,0) -- (1,0,0);
\draw[->] (0,0,0) -- (0,1,0);
\draw[->] (0,0,0) -- (0,0,1);
\draw[canvas is xy plane at z=0,lightgray] (0,0) grid (3,3);
% define where the red coordinate system should be
\coordinate (A) at (1,1,0);
% draw the red coordinate system at (A)
\begin{pose}[origin=(A)]
\draw[->,red] (0,0,0) -- (1,0,0);
\draw[->,red] (0,0,0) -- (0,1,0);
\draw[->,red] (0,0,0) -- (0,0,1);
\draw[->,red] (0,0,0) -- (1,1,1);
\end{pose}
% draw the green coordinate system at (1,1,0)
\begin{pose}[x=1,y=1,z=0]
\draw[->,green] (0,0,0) -- (1,0,0);
\draw[->,green] (0,0,0) -- (0,1,0);
\draw[->,green] (0,0,0) -- (0,0,1);
\draw[->,green] (0,0,0) -- (1,1,1);
\end{pose}
\end{tikzpicture}
\end{document}
除了旋转部分,环境在原则上是可以工作的,但旋转不是这里问题的一部分。您会看到,绿色坐标系正确地绘制在 (1,1,0)。但红色坐标系绘制在 (0,0,0) 而不是 (A)。这是因为实现尚未完成。显然,标记为 的行处的实现不### MODIFY CODE HERE ###
正确。
我该用什么来替换该代码?
答案1
正如我在评论中所说,根本问题在于
\coordinate (A) at (1,1,0);
仅存储点的二维表示(A)
。
使用pgfkeys
我们可以定义一个新命令\tdcoord
来存储三维表示。然后我们将您的密钥定义为从存储的信息中设置和的origin
样式。x
y
z
我选择的实现将存储\tdcoord (A) at (3,1,0)
在 下的一组x
、y
和z
键中/tdcoords/(A)/
。(td
用于三维)。然后我们可以通过\pgfkeysvalueof{/tdcoords/(A)/x}
等提取值。
\documentclass{article}
\usepackage{tikz}
\usepackage{tikz-3dplot}
\usetikzlibrary{3d}
% fix wrong implementation of xy canvas
\makeatletter
\tikzoption{canvas is xy plane at z}[]{%
\def\tikz@plane@origin{\pgfpointxyz{0}{0}{#1}}%
\def\tikz@plane@x{\pgfpointxyz{1}{0}{#1}}%
\def\tikz@plane@y{\pgfpointxyz{0}{1}{#1}}%
\tikz@canvas@is@plane
}
\makeatother
\pgfkeys{%
/poseenv/.is family, /poseenv,%
% set the defaut values
default/.style = {%
x = 0,%
y = 0,%
z = 0,%
roll = 0,%
pitch = 0,%
yaw = 0%
},%
x/.estore in = \poseenvx,%
y/.estore in = \poseenvy,%
z/.estore in = \poseenvz,%
roll/.estore in = \poseenvroll,%
pitch/.estore in = \poseenvpitch,%
yaw/.estore in = \poseenvyaw,%
origin/.style={\pgfkeysifdefined{/tdcoords/#1}{%
x=\pgfkeysvalueof{/tdcoords/#1/x},
y=\pgfkeysvalueof{/tdcoords/#1/y},
z=\pgfkeysvalueof{/tdcoords/#1/z}}{/tdcoords/#1}}%
}%
\def\tdcoord #1 at (#2,#3,#4);{\pgfkeys{/tdcoords/#1/.is
family,/tdcoords/#1,x/.initial=#2,y/.initial=#3,z/.initial=#4}
\coordinate #1 at (#2,#3,#4);}
\newenvironment{pose}[1][]%
{%
% parse arguments
\pgfkeys{/poseenv, default, #1}%
% modify 3dplot's rotated coords according to \poseenv{x,y,z,roll,pitch,yaw}
\coordinate (origin) at (\poseenvx,\poseenvy,\poseenvz);
\tdplotsetrotatedcoordsorigin{(origin)}
% todo: do rotation
% begin the scope
\begin{scope}[tdplot_rotated_coords,transform shape]
}%
{%
% end the scope
\end{scope}
}%
\begin{document}
\tdplotsetmaincoords{80}{45}
\begin{tikzpicture}[tdplot_main_coords]
% draw a coordinate system in black at the origin
\draw[->] (0,0,0) -- (1,0,0);
\draw[->] (0,0,0) -- (0,1,0);
\draw[->] (0,0,0) -- (0,0,1);
\draw[canvas is xy plane at z=0,lightgray] (0,0) grid (3,3);
% define where the red coordinate system should be
\tdcoord (A) at (3,1,0);
% draw the red coordinate system at (A)
\begin{pose}[origin=(A)]
\draw[->,red] (0,0,0) -- (1,0,0);
\draw[->,red] (0,0,0) -- (0,1,0);
\draw[->,red] (0,0,0) -- (0,0,1);
\draw[->,red] (0,0,0) -- (1,1,1);
\end{pose}
% draw the green coordinate system at (1,1,0)
\begin{pose}[x=1,y=1,z=0]
\draw[->,green] (0,0,0) -- (1,0,0);
\draw[->,green] (0,0,0) -- (0,1,0);
\draw[->,green] (0,0,0) -- (0,0,1);
\draw[->,green] (0,0,0) -- (1,1,1);
\end{pose}
\end{tikzpicture}
\end{document}
请注意,\pgfkeysvalueof
不会对给定的键是否已定义进行错误检查,因此我将origin
样式代码包装在\pgfkeysifdefined
测试顶部键是否存在中/tdcoords/#1
,其中#1
传递给的值origin
。如果不存在,我会调用/tdcoords/#1
,然后会失败并显示一个合理易懂的错误消息。