通过 pgfkeys 传递 3d 坐标

通过 pgfkeys 传递 3d 坐标

我正在使用 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样式。xyz

我选择的实现将存储\tdcoord (A) at (3,1,0)在 下的一组xyz键中/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,然后会失败并显示一个合理易懂的错误消息。

相关内容