我是 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}
\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[总是向右] 和纸是[总是向上])?
键x
,y
并且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 图形,请选择其他能够实现这一点的工具,例如
- 渐近线,
- pst-solids3d,
- pgf图(用于绘图)
- 或任何其他可以生成可包含在 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 如何处理坐标。
(x,y)
或类型的坐标(x,y,z)
被解释为x
当前 x 向量的乘积,加上y
y 向量和z
z 向量的乘积。这些向量都是 2D 向量,因此结果也是 2D 向量,无论原始向量是 2D 还是 3D。- 将当前坐标变换矩阵应用于此向量。这是一个 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 cm
和show xyz
是诊断性的,因此您可以在日志文件或控制台中看到当前向量和矩阵。键xy
和xyz
允许您一次性指定两个或三个向量(TikZ 只提供了一种一次指定一个向量的方法,这是一个问题 - 例如,x={(0,1)}, y={(1,0)}
应该交换x
,y
但是没有)。
现在,在您的代码中,您还将坐标转换传输到画布。通常,这不是您想要的,因为这也会转换节点文本,所以我没有包含该部分。