通过给定的旋转和平移角度进行坐标和画布变换

通过给定的旋转和平移角度进行坐标和画布变换

我是 TikZ 的新手,所以我正在阅读 TikZ 文档。在第 1155 页(第 108 章)上,我找到了有关变换的信息。CTM(坐标变换矩阵)由四个数字 a、b、c 和 d 组成。因此,我尝试使用多年前在 postscript 中测试过的矩阵。但不幸的是,我无法获得所需的结果。我看不出我做错了什么,所以我寻求帮助。y' 和 z' 轴似乎是正确的,但 x' 轴的方向不正确。这是我的 MWE:

\documentclass[tikz]{standalone}

\def\Angtheta{0}%       Rotation arround z-Axis bzw. vertical axis through (1cm, 0, 0) -> see x-shift
\def\Angphi{60}%        Rotation to x-y-plane: 90-\phi
\def\AngLG{45}%         Angle for the x-Axis
\def\VK{0.5*sqrt(2)}%   shortening of the x-Axis is 0.5*sqrt(2)
\def\xO{1cm}%           shift in x-direction (in x-y-z-coordinate-system)
\def\yO{0cm}%           shift in y-direction (in x-y-z-coordinate-system)
\def\zO{0cm}%           shift in z-direction (in x-y-z-coordinate-system)

\begin{document}

\begin{tikzpicture}
    [%
        x={({cos(180-\AngLG)*\VK*1cm},{-sin(180-\AngLG)*\VK*1cm})},% (-0.5cm,-0.5cm) means in this case the same
        y={(1cm,0cm)},% (1cm,0cm)
        z={(0 cm, 1 cm)}
    ]

    \coordinate (O) at (0,0,0);
    \coordinate (B) at (0,2,1.5);
    \coordinate (X) at (2,0,0);
    \coordinate (Y) at (0,2,0);
    \coordinate (Z) at (0,0,1.5);

    \draw[->] (O) -- (X) node[pos=1.1]{$x$};
    \draw[->] (O) -- (Y) node[pos=1.1]{$y$};
    \draw[->] (O) -- (Z) node[pos=1.1]{$z$};

\begin{scope}
    % \pgftransformreset% seems to have no effect here
    \pgftransformcm {cos(\Angtheta)+\VK*sin(\Angtheta)*cos(\AngLG)}%    a in xT = a*x + c*y + s
                    {\VK*sin(\Angtheta)*sin(\AngLG)}%                   b in yT = b*x + d*y + t
                    {-sin(\Angphi)*sin(\Angtheta)+\VK*sin(\Angphi)*cos(\Angtheta)*cos(\AngLG)}% c
                    {cos(\Angphi)+\VK*sin(\Angphi)*cos(\Angtheta)*sin(\AngLG)}% d
                    {\pgfpoint
                        {\yO-\VK*\xO*cos(\AngLG)}%  s
                        {\zO-\VK*\xO*sin(\AngLG)}%  t
                    }%
    \pgfgettransformentries{\macroA}{\macroB}{\macroC}{\macroD}{\macroE}{\macroF}
    \pgftransformreset
    \pgfsettransformentries{\macroA}{\macroB}{\macroC}{\macroD}{\macroE}{\macroF}
    \pgflowlevelsynccm %%  command to concatenate the canvas transformation matrix
                        %  with the current coordinate transformation matrix (CTM)
 
    \draw[->,thick,color=blue] (O) -- (X) node[pos=1.1]{$x'$};
    \draw[->,thick,color=blue] (O) -- (Y) node[pos=1.1]{$y'$};
    \draw[->,thick,color=blue] (O) -- (Z) node[pos=1.1]{$z'$};
\end{scope}
\end{tikzpicture}
\end{document}

在此处输入图片描述

以下是 NMWE:

\documentclass[tikz]{standalone}
\usetikzlibrary{angles,arrows,arrows.meta,patterns}

\def\Angtheta{80}%      Rotation arround z-Axis bzw. vertical axis through (1cm, 0, 0) -> see x-shift
\def\Angphi{60}%        Rotation to x-y-plane: 90-\phi
\def\AngLG{45}%         Angle for the x-Axis
\def\VK{0.5*sqrt(2)}%   shortening of the x-Axis is 0.5*sqrt(2)
\def\xO{1cm}%           shift in x-direction (in x-y-z-coordinate-system)
\def\yO{0cm}%           shift in y-direction (in x-y-z-coordinate-system)
\def\zO{0cm}%           shift in z-direction (in x-y-z-coordinate-system)

\begin{document}

\begin{tikzpicture}
    [%
        x={({cos(180-\AngLG)*\VK*1cm},{-sin(180-\AngLG)*\VK*1cm})},% (-0.5cm,-0.5cm)
        y={(1cm,0cm)},% (1cm,0cm)
        z={(0 cm, 1 cm)}
    ]

    \coordinate (O) at (0,0,0);
    \coordinate (B) at (0,2,1.5);
    \coordinate (X) at (2,0,0);
    \coordinate (Y) at (0,2,0);
    \coordinate (Z) at (0,0,1.5);

    \draw[->] (O) -- (X) node[pos=1.1]{$x$};
    \draw[->] (O) -- (Y) node[pos=1.1]{$y$};
    \draw[->] (O) -- (Z) node[pos=1.1]{$z$};

\begin{scope}
    % \pgftransformreset% seems to have no effect here
    \pgftransformcm {cos(\Angtheta)+\VK*sin(\Angtheta)*cos(\AngLG)}%    a in xT = a*x + c*y + s
                    {\VK*sin(\Angtheta)*sin(\AngLG)}%                   b in yT = b*x + d*y + t
                    {-sin(\Angphi)*sin(\Angtheta)+\VK*sin(\Angphi)*cos(\Angtheta)*cos(\AngLG)}% c
                    {cos(\Angphi)+\VK*sin(\Angphi)*cos(\Angtheta)*sin(\AngLG)}% d
                    {\pgfpoint
                        {\yO-\VK*\xO*cos(\AngLG)}%  s
                        {\zO-\VK*\xO*sin(\AngLG)}%  t
                    }%
    \pgfgettransformentries{\macroA}{\macroB}{\macroC}{\macroD}{\macroE}{\macroF}
    \pgftransformreset
    \pgfsettransformentries{\macroA}{\macroB}{\macroC}{\macroD}{\macroE}{\macroF}
    \pgflowlevelsynccm %%  command to concatenate the canvas transformation matrix
                        %  with the current coordinate transformation matrix (CTM)
 
    \draw[->,thick,color=blue] (O) -- (X) node[pos=1.1]{$x'$};
    \draw[->,thick,color=blue] (O) -- (Y) node[pos=1.1]{$y'$};
    \draw[->,thick,color=blue] (O) -- (Z) node[pos=1.1]{$z'$};
    
    \draw[color=red,pattern=crosshatch,pattern color=gray!20] (O) rectangle (B) ;
    \draw[dashed,gray] (O) -- (B) ;
    
    \draw %(Z) -- (B) -- (Y) % draw right angle
        pic (right1) [draw=green!50!black,fill=yellow,fill opacity=0.4,angle eccentricity=0.55,
                angle radius=5mm,pic text=] {angle = Z--B--Y};
        \fill[gray] (right1) circle [radius=0.75pt];
    \draw %(X) -- (O) -- (B) % draw angle beta
        pic (beta) [->,>={Latex[length=2pt]},draw=cyan!30!black,fill=cyan,fill opacity=0.4,angle eccentricity=0.7,
                text opacity=0.6, angle radius=7mm,pic text={\scriptsize$\beta$}] {angle = Y--O--B};
    
    \pgftransformshift{\pgfpoint{1cm}{1.3cm}}%  shifting the text in the new coordinate-system
    \pgftext{test}
\end{scope}
\end{tikzpicture}
\end{document}

在此处输入图片描述

CTM 代码

在此处输入图片描述

\gamma 是负 x 轴和 y 轴之间的角度

缩短系数 r 缩短 x 轴

绕 z 轴旋转 bzw. 垂直轴 \theta

旋转至 xy 平面:90-\phi

在下一个例子中,我选择phi=90并且theta=-90 在这种情况下,x'-轴应该与-轴平行z在此处输入图片描述

编辑

更精确地表述问题

我需要一个 3D 坐标系来进行平行投影,其中 y 轴在右,z 轴在上,负 x 轴与 y 轴成 45° 角(在某些情况下可能会有所不同)。我还需要一个 x 轴的缩短因子,通常为 0.5*sqrt(2)(有时为 0.5)。各种物体都要在这个坐标系中绘制,例如金字塔或平面。应以正确的透视图将角度绘制到这些物体中。在这种情况下,直接使用角度 theta 和 phi 是不切实际的,但这两个角度可以从法线向量甚至 3 个点或两个方向向量计算出来。在所示的示例中,从三个点计算是合适的,其中一个点将坐标原点映射到角度的顶点。在下面的例子中,我没有系统地计算这一点。

我想要一个宏,通过指定之前定义为节点的 3 个点(或 2 个角度,或 2 个方向向量,或一个法线向量)来执行这种转换。

代码

\documentclass[tikz]{standalone}
\usetikzlibrary{angles,arrows,arrows.meta,patterns,calc}

\def\Angtheta{-45}%     Rotation arround z-Axis bzw. vertical axis through (1cm, 0, 0) -> see x-shift
\def\Angphi{0}%         Rotation to x-y-plane: 90-\phi
\def\AngLG{45}%         Angle for the x-Axis
\def\VK{0.5*sqrt(2)}%   shortening of the x-Axis is 0.5*sqrt(2)
\def\xO{0cm}%           shift in x-direction (in x-y-z-coordinate-system)
\def\yO{0cm}%           shift in y-direction (in x-y-z-coordinate-system)
\def\zO{0cm}%           shift in z-direction (in x-y-z-coordinate-system)

% for schools in german: parallel projection with #1 angle between
% negative x-axis and y-axis and #2=shortening of x-axis 
\tikzset{%
    3D-KoSys/.code n args={2}{%
    \tikzset{%
    x={({cos(180-#1)*(#2)*1cm},{-sin(180-#1)*(#2)*1cm})},% (-0.5cm,-0.5cm)
    y={(1cm,0cm)},% 
    z={(0 cm, 1 cm)}%
    }%
}%
}

\tikzset{%
    projectTP/.code n args={5}{% #1,#2,#3 -> xO,yO,zO shifting;  #4=theta, #5=phi
        \pgftransformcm 
        {cos(#4)+\VK*sin(#4)*cos(\AngLG)}%                      a in xT = a*x + c*y + s
        {\VK*sin(#4)*sin(\AngLG)}%                              b in yT = b*x + d*y + t
        {-sin(#5)*sin(#4)+\VK*sin(#5)*cos(#4)*cos(\AngLG)}%     c in xT = a*x + c*y + s
        {cos(#5)+\VK*sin(#5)*cos(#4)*sin(\AngLG)}%              d in yT = b*x + d*y + t
        {\pgfpoint
            {#2-\VK*#1*cos(\AngLG)}%                            s in xT = a*x + c*y + s
            {#3-\VK*#1*sin(\AngLG)}%                            t in yT = b*x + d*y + t
        }%
        \pgflowlevelsynccm%
    }%
}%

\def\myprojection(#1,#2,#3)#4#5{% #1,#2,#3 -> xO,yO,zO shifting;  #4=theta, #5=phi, see below
projectTP={#1}{#2}{#3}{#4}{#5}%
}

\def\germanrightangle(#1,#2,#3){%
\draw % % draw german right angle
        pic (right1) [draw=black!70,fill=gray!50,fill opacity=0.4,angle eccentricity=0.55,
                angle radius=2mm,pic text=] {angle = #1--#2--#3};%
        \fill[black!70] (right1) circle [radius=0.5pt];%
}

\def\markmyangle(#1,#2,#3)#4{%
\draw % % draw angle
        pic (beta) [->,>={Latex[length=2pt]},draw=black!70,fill=cyan!40,fill opacity=0.4,angle eccentricity=0.7,
                text opacity=0.6, angle radius=7mm,pic text={\scriptsize#4}] {angle = #1--#2--#3};%
}

\begin{document}

\begin{tikzpicture}[%
    3D-KoSys={45}{0.5*sqrt(2)},
    ]

    \coordinate (O) at (0,0,0);
    \coordinate (A) at (2,0,0);
    \coordinate (B) at (2,2,0);
    \coordinate (C) at (0,2,0);
    \coordinate (M) at (1,1,0);
    \coordinate (S) at (1,1,2.5);
    \coordinate (X) at (3,0,0);
    \coordinate (Y) at (0,3,0);
    \coordinate (Z) at (0,0,2.5);

   % set new origin O'= M', so that x --> 0, y --> y'*cos(45)???, z --> z'
    \coordinate (M') at (0,0,0);%    (0, 0 , 0)
    \coordinate (S') at (0,0,2.5);%  (0, 0, 2.5)
    \coordinate (C') at (0,1.4142,0);%  (0, y*cos(45), 0)

    \draw[->] (O) -- (X) node[pos=1.1]{$x$};
    \draw[->] (O) -- (Y) node[pos=1.1]{$y$};
    \draw[->] (O) -- (Z) node[pos=1.1]{$z$};

    \draw[gray] (O) -- (A) -- (B) -- (C) -- cycle ;
    \draw[gray,dashed] (O) -- (S) (M) -- (S) (A) -- (C) (O) -- (B);
    \draw[gray] (A) -- (S) (B) -- (S) (C) -- (S);
    \fill[yellow,fill opacity=0.4] (A) -- (B) -- (S) -- cycle ;

   % set new origin O'= M', so that x --> 0, y --> y'*cos(45)???, z --> z'
   \coordinate (M') at (0,0,0);%    (0, 0 , 0)
   \coordinate (S') at (0,0,2.5);%  (0, 0, 2.5)
   \coordinate (C') at (0,1.4142,0);%  (0, y*cos(45), 0)

 \begin{scope}[projectTP={1cm}{1cm}{0cm}{45}{0}]
    \markmyangle(S',C',M'){$\beta$}
    \germanrightangle(C,M',S')
%    \pgftransformshift{\pgfpoint{1cm}{1.3cm}}%  shifting the text in the new coordinate-system
    \pgftext{\tiny O}
 \end{scope}

    \coordinate (B'') at (0,1.4142,0);%  (0, y*cos(-45), 0)

 \begin{scope}[projectTP={1cm}{1cm}{0cm}{-45}{0}]
    \markmyangle(S',B'',M'){$\alpha$}
    % \germanrightangle(B'',M',S')
 \end{scope}

    \coordinate (A''') at (0,0,0);%  (0, y*cos(-45), 0)
    \coordinate (B''') at (0,2,0);%  (0, y*cos(-45), 0)
    \coordinate (S''') at (0,1,2.6926);%  (0, z/sin(68,1986), 0)
    
 \begin{scope}[projectTP={2cm}{0cm}{0cm}{0}{21.8}]% arctan(2.5/1)=68.1986
    \markmyangle(B''',A''',S'''){$\delta$}
    \pgftransformshift{\pgfpoint{1cm}{1.2cm}}%  shifting the text in the new coordinate-system
    \pgftext{\shortstack{\tiny Thank you!\\
    \tiny Qrrbrbirlbel\\ \tiny + Andrew S.}}
 \end{scope}

\end{tikzpicture}

\end{document}

在此处输入图片描述

感谢您的帮助!

答案1

我相信您想要实现的目标在 TikZ 中无法实现。

首先,你的公式只使用X, 绝不角度γ可能表示绕纸轴(垂直于纸X[总是向右] 和纸[总是向上])?

xy并且z只将 3D 点转换为纸上的 2D 点,并且然后发生PGF转变。

例如,坐标坐标系设置类似

x = (-135, sqrt(2)) = (-1cm, -1cm)
y = ( 0: 1cm)       = ( 1cm,  0cm)
z = (90: 1cm)       = ( 0cm,  1cm)

坐标(-1, 0, 0)(0, 1, 1)完全相同:

canvas x = 1cm
canvas y = 1cm

或者简单地(1cm, 1cm)帆布CS

此时,TikZ、PGF 或任何转换都无法区分这两者。


在下面的代码中,我将您的公式转换为\pgftramsformcmRot宏。无论您为三个角度选择什么值,黑线((-1, 0, 0))和红线((0, 1, 1))始终相同。

如果你真的想制作精美的 3D 图形,请选择其他能够实现这一点的工具,例如

  • (用于绘图)
  • 或任何其他可以生成可包含在 LaTeX 中的(矢量)图像的软件。

代码

\documentclass[tikz]{standalone}
\newcommand*\pgftransformcmRot[4][.70710678118]{% #2 = theta
                                                % #3 = phi
                                                % #4 = gamma
  \pgftransformcm {cos(#2)+#1*sin(#2)*cos(#4)}
                  {#1*sin(#2)*sin(#4)}
                  {-sin(#3)*sin(#2)+#1*sin(#3)*cos(#2)*cos(#4)}
                  {cos(#3)+#1*sin(#3)*cos(#2)*sin(#4)}}
\begin{document}
\begin{tikzpicture}[x={(-1cm,-1cm)}, y=(0:1cm), z=(90:1cm)]
\path[->, ultra thick, blue] (0,0,0) edge (1,0,0) edge (0,1,0) edge (0,0,1);

\draw[thick] (0,0,0) -- (-1,0,0);
\draw[red]   (0,0,0) -- ( 0,1,1);
\end{tikzpicture}

\begin{tikzpicture}
\useasboundingbox (-2,-2) (2,2);
\tikzset{x={(-1cm,-1cm)}, y=(0:1cm), z=(90:1cm)}
\pgftransformcmRot{0}{45}{0}{\pgfpointorigin}\pgflowlevelsynccm
\path[->, ultra thick, blue] (0,0,0) edge (1,0,0) edge (0,1,0) edge (0,0,1);

\draw[thick] (0,0,0) -- (-1,0,0);
\draw[red]   (0,0,0) -- ( 0,1,1);
\end{tikzpicture}
\end{document}

答案2

重要的是要记住,TikZ/PGF 是作为 2D 绘图系统设计的,而使用 3D 坐标的能力是其上的一个额外层。这意味着其所有方法都是为 2D 技术设置的。

为了理解其含义,值得研究一下 TikZ/PGF 如何处理坐标。

  1. (x,y)或类型的坐标(x,y,z)被解释为x当前 x 向量的乘积,加上yy 向量和zz 向量的乘积。这些向量都是 2D 向量,因此结果也是 2D 向量,无论原始向量是 2D 还是 3D。
  2. 将当前坐标变换矩阵应用于此向量。这是一个 2D 矩阵和 2D 向量(表示平移)。

现在,它具有足够的灵活性来实现从 R^3 到 R^2 的任何仿射变换,但您不能使用它的原生变换技术来操纵变换矩阵的 3D 部分。您必须手动指定它。

以下代码实现了 3D 旋转矩阵(由 Tait-Bryan 角指定),其 2D 投影如下:

[1 0 1/sqrt(2)]
[0 1 1/sqrt(2)]

这只是一个例子,表明这是可能的。如果你想更全面地做到这一点,那么你可以实现实际的 3x3 矩阵乘法,以便更容易指定变换。

\documentclass{article}
%\url{https://tex.stackexchange.com/q/653314/86}
\usepackage{tikz}

\makeatletter

\tikzset{
  show cm/.code={
    \pgfgettransform\@cm\show\@cm
  },
  show xyz/.code={
    \edef\@xyz{%
      (\the\pgf@xx,\the\pgf@xy), %
      (\the\pgf@yx,\the\pgf@yy), %
      (\the\pgf@zx,\the\pgf@zy)%
    }%
    \show\@xyz
  },
  xy/.code 2 args={%
    \tikz@scan@one@point\pgfutil@firstofone#1\relax
    \pgf@xa=\pgf@x
    \pgf@ya=\pgf@y
    \tikz@scan@one@point\pgfutil@firstofone#2\relax
    \pgf@yx=\pgf@x
    \pgf@yy=\pgf@y
    \pgf@xx=\pgf@xa
    \pgf@xy=\pgf@ya
  },
  xyz/.code n args={3}{%
    \tikz@scan@one@point\pgfutil@firstofone#1\relax
    \pgf@xa=\pgf@x
    \pgf@ya=\pgf@y
    \tikz@scan@one@point\pgfutil@firstofone#2\relax
    \pgf@xb=\pgf@x
    \pgf@yb=\pgf@y
    \tikz@scan@one@point\pgfutil@firstofone#3\relax
    \pgf@zx=\pgf@x
    \pgf@zy=\pgf@y
    \pgf@yx=\pgf@xb
    \pgf@yy=\pgf@yb
    \pgf@xx=\pgf@xa
    \pgf@xy=\pgf@ya
    \pgf@xa=\pgf@x
    \pgf@ya=\pgf@y
  },
  rotate 3D/.code n args={3}{%
    \tikzset{
      xyz={%
        (
        {cos(#1) * cos(#2) - sin(#2)/sqrt(2)},
        {sin(#1) * cos(#2) - sin(#2)/sqrt(2)},
        )
      }{%
        (
        {cos(#1) * sin(#2) * sin(#3) - sin(#1) * cos(#3) + cos(#2) * sin(#3)/sqrt(2)},
        {sin(#1) * sin(#2) * sin(#3) + cos(#1) * cos(#3) + cos(#2) * sin(#3)/sqrt(2)},
        )
      }{%
        (
        {cos(#1) * sin(#2) * cos(#3) + sin(#1) * sin(#3) + cos(#2) * cos(#3)/sqrt(2)},
        {sin(#1) * sin(#2) * cos(#3) - cos(#1) * sin(#3) + cos(#2) * cos(#3)/sqrt(2)},
        )
      }
    }
  }
}

\makeatother

\begin{document}
\begin{tikzpicture}[
  rotate 3D={20}{40}{10},
  show xyz,
  show cm,
]

\draw[->] (0,0,0) -- (1,0,0) node[above] {\(x\)};
\draw[->] (0,0,0) -- (0,1,0) node[above] {\(y\)};
\draw[->] (0,0,0) -- (0,0,1) node[above] {\(z\)};


\end{tikzpicture}
\end{document}

它还增加了一些额外功能。键show cmshow xyz是诊断性的,因此您可以在日志文件或控制台中看到当前向量和矩阵。键xyxyz允许您一次性指定两个或三个向量(TikZ 只提供了一种一次指定一个向量的方法,这是一个问题 - 例如,x={(0,1)}, y={(1,0)} 应该交换xy但是没有)。

现在,在您的代码中,您还将坐标转换传输到画布。通常,这不是您想要的,因为这也会转换节点文本,所以我没有包含该部分。

相关内容