![如何编写一个好的矢量解析器,可以执行 \pgfvecparse{\A=\B-\C; \D=\E x \F;}](https://linux22.com/image/393249/%E5%A6%82%E4%BD%95%E7%BC%96%E5%86%99%E4%B8%80%E4%B8%AA%E5%A5%BD%E7%9A%84%E7%9F%A2%E9%87%8F%E8%A7%A3%E6%9E%90%E5%99%A8%EF%BC%8C%E5%8F%AF%E4%BB%A5%E6%89%A7%E8%A1%8C%20%5Cpgfvecparse%7B%5CA%3D%5CB-%5CC%3B%20%5CD%3D%5CE%20x%20%5CF%3B%7D.png)
我经常使用点的坐标来绘制几何图形。我知道,我们可以添加、减去点的坐标,例如
\begin{tikzpicture}
\tkzDefPoints{0/0/C',3/0/D',1/1/B'}
\coordinate (A') at ($(B')+(D')-(C')$);
\end{tikzpicture}
如果我有两个点A(1,2,3)
和B(4,5,6)
,我该如何将向量定义AB
为(\B)-(\A)
?
答案1
如果仅将坐标用于绘图,则只需将点的每个组成部分定义为变量,然后使用它们定义坐标点。例如:
\documentclass[margin=3.14159mm]{standalone}
\usepackage{tikz,tikz-3dplot}
\begin{document}
\tdplotsetmaincoords{60}{125}
\begin{tikzpicture}
[scale=0.9,
tdplot_main_coords,
axis/.style={-latex,thick},
vector/.style={-stealth,red,very thick},
vector guide/.style={dashed,thick}]
%standard tikz coordinate definition using x, y, z coords
% A(2,4,3), B(3,-1,4)
\def\Ax{2}
\def\Ay{4}
\def\Az{3}
\def\Bx{-1}
\def\By{3}
\def\Bz{4}
\coordinate (O) at (0,0,0);
\coordinate (A) at (\Ax,\Ay,\Az);
\coordinate (B) at (\Bx,\By,\Bz);
%draw axes
\draw[axis] (0,0,0) -- (4,0,0) node[anchor=north east]{$x$};
\draw[axis] (0,0,0) -- (0,4,0) node[anchor=north west]{$y$};
\draw[axis] (0,0,0) -- (0,0,5) node[anchor=south]{$z$};
%Dot at point
\fill [blue] (A) circle (2pt);
\fill [blue] (B) circle (2pt);
%draw a vector from O to A and O to B
\draw[vector guide] (O)node[left=1mm]{} -- (A)node[above=-1mm,right]{$P_1(\Ax,\Ay,\Az)$};
\draw[vector guide] (O) -- (B)node[above=-1mm,right]{$P_2(\Bx,\By,\Bz)$};
%draw vector D=AB
\draw[vector] (A) -- (B)node[midway,above,sloped]{$\mathbf{D}$};
\end{tikzpicture}
\end{document}
补充
在得到回答者的许可后,我(Steven B Segletes)在此展示了如何 listofitems
使用该包来简化语法,并可能提供更高的可读性。有了它,我可以通过读取列表来创建数组,语法为\readlist\A{2,4,3}
。然后,表达式\A[]
将返回数组2,4,3
,这足以在当前 MWE 中使用。但是,各个组件也可以作为\A[1]
、\A[2]
和来访问\A[3]
,可以根据需要用于各种计算。
\documentclass[margin=3.14159mm]{standalone}
\usepackage{tikz,tikz-3dplot,listofitems}
\begin{document}
\tdplotsetmaincoords{60}{125}
\begin{tikzpicture}
[scale=0.9,
tdplot_main_coords,
axis/.style={-latex,thick},
vector/.style={-stealth,red,very thick},
vector guide/.style={dashed,thick}]
%standard tikz coordinate definition using x, y, z coords
% A(2,4,3), B(3,-1,4)
\readlist\A{2,4,3}
\readlist\B{-1,3,4}
\coordinate (O) at (0,0,0);
\coordinate (A) at (\A[]);
\coordinate (B) at (\B[]);
%draw axes
\draw[axis] (0,0,0) -- (4,0,0) node[anchor=north east]{$x$};
\draw[axis] (0,0,0) -- (0,4,0) node[anchor=north west]{$y$};
\draw[axis] (0,0,0) -- (0,0,5) node[anchor=south]{$z$};
%Dot at point
\fill [blue] (A) circle (2pt);
\fill [blue] (B) circle (2pt);
%draw a vector from O to A and O to B
\draw[vector guide] (O)node[left=1mm]{} -- (A)node[above=-1mm,right]{$P_1(\A[])$};
\draw[vector guide] (O) -- (B)node[above=-1mm,right]{$P_2(\B[])$};
%draw vector D=AB
\draw[vector] (A) -- (B)node[midway,above,sloped]{$\mathbf{D}$};
\end{tikzpicture}
\end{document}
答案2
只是为了好玩,我编写了 3D 向量加法、减法、叉积和点积(标量视为 1D 向量)的例程。我试图实际解析 \A+\B 形式的表达式,但最终放弃了。
\documentclass{article}
\usepackage{listofitems}
\usepackage{pgfmath}
\usepackage{amsmath}
\makeatletter
\newcommand{\@vecargs}{}% reserve global names
\newcommand{\vecadd}{}
\newcommand{\vecsub}{}
\newcommand{\vecdot}{}
\newcommand{\veccross}{}
\newcommand{\vecparse}{}
\def\vecadd#1#2#3% #1 = #2 + #3
{\bgroup% local definitions
\pgfmathsetmacro{\@x}{#2[1]+#3[1]}%
\pgfmathsetmacro{\@y}{#2[2]+#3[2]}%
\pgfmathsetmacro{\@z}{#2[3]+#3[3]}%
\xdef\@vecargs{\@x,\@y,\@z}%
\egroup
\readlist#1{\@vecargs}}
\def\vecsub#1#2#3% #1 = #2 - #3
{\bgroup% local definitions
\pgfmathsetmacro{\@x}{#2[1]-#3[1]}%
\pgfmathsetmacro{\@y}{#2[2]-#3[2]}%
\pgfmathsetmacro{\@z}{#2[3]-#3[3]}%
\xdef\@vecargs{\@x,\@y,\@z}%
\egroup
\readlist#1{\@vecargs}}
\def\vecdot#1#2#3% #1 = #2 \cdot #3
{\pgfmathsetmacro{\@vecargs}{#2[1]*#3[1] + #2[2]*#3[2] + #2[3]*#3[3]}%
\readlist#1{\@vecargs}}
\def\veccross#1#2#3% #1 = #2 \times #3
{\bgroup% local definitions
\pgfmathsetmacro{\@x}{#2[2]*#3[3] - #2[3]*#3[2]}%
\pgfmathsetmacro{\@y}{#2[3]*#3[1] - #2[1]*#3[3]}%
\pgfmathsetmacro{\@z}{#2[1]*#3[2] - #2[2]*#3[1]}%
\xdef\@vecargs{\@x,\@y,\@z}%
\egroup
\readlist#1{\@vecargs}}
\makeatother
\begin{document}
\readlist\A{1,2,3}
\readlist\B{4,5,6}
\vecadd\C\A\B
\C[]
\vecsub\C\A\B
\C[]
\vecdot\C\A\B
\C[]
\veccross\C\A\B
\C[]
\end{document}
补充
我希望 John 不介意我 (Steven B Segletes) 将他备受追捧的解析器添加到代码中。这样可以输入\vecparse\C{\A+\B}
、\vecparse\C{\A - \B}
、\vecparse\C{\A .\B}
和形式的内容\vecparse\C{\A x\B}
(额外的空格无所谓)。
不仅增加了对 的支持,\vecparse\C{\A x\B}
还增加了对和的支持。\vecparse\C{\A x(3,5,6)}
\vecparse\C{(3,5,6)x\B}
\vecparse\C{(1,1,1)x(1,2,3)}
\documentclass{article}
\usepackage{listofitems}
\usepackage{pgfmath}
\usepackage{amsmath}
\makeatletter
\newcommand{\@vecargs}{}% reserve global names
\newcommand{\vecadd}{}
\newcommand{\vecsub}{}
\newcommand{\vecdot}{}
\newcommand{\veccross}{}
\newcommand{\vecparse}{}
\def\vecadd#1#2#3% #1 = #2 + #3
{\bgroup% local definitions
\pgfmathsetmacro{\@x}{#2[1]+#3[1]}%
\pgfmathsetmacro{\@y}{#2[2]+#3[2]}%
\pgfmathsetmacro{\@z}{#2[3]+#3[3]}%
\xdef\@vecargs{\@x,\@y,\@z}%
\egroup
\setsepchar{,}%
\readlist#1{\@vecargs}}
\def\vecsub#1#2#3% #1 = #2 - #3
{\bgroup% local definitions
\pgfmathsetmacro{\@x}{#2[1]-#3[1]}%
\pgfmathsetmacro{\@y}{#2[2]-#3[2]}%
\pgfmathsetmacro{\@z}{#2[3]-#3[3]}%
\xdef\@vecargs{\@x,\@y,\@z}%
\egroup
\setsepchar{,}%
\readlist#1{\@vecargs}}
\def\vecdot#1#2#3% #1 = #2 \cdot #3
{\pgfmathsetmacro{\@vecargs}{#2[1]*#3[1] + #2[2]*#3[2] + #2[3]*#3[3]}%
\setsepchar{,}%
\readlist#1{\@vecargs}}
\def\veccross#1#2#3% #1 = #2 \times #3
{\bgroup% local definitions
\pgfmathsetmacro{\@x}{#2[2]*#3[3] - #2[3]*#3[2]}%
\pgfmathsetmacro{\@y}{#2[3]*#3[1] - #2[1]*#3[3]}%
\pgfmathsetmacro{\@z}{#2[1]*#3[2] - #2[2]*#3[1]}%
\xdef\@vecargs{\@x,\@y,\@z}%
\egroup
\setsepchar{,}%
\readlist#1{\@vecargs}}
\def\vecparse#1#2{%
\setsepchar{+||-||x||./(||)}%
\readlist*\@findop{#2}%
\ifnum\listlen\@findop[1]=1\relax
\itemtomacro\@findop[1]\tmpA
\else
\itemtomacro\@findop[1,2]\tmpF
\setsepchar{,}%
\readlist\tmpE{\tmpF}%
\def\tmpA{\tmpE}%
\fi
\ifnum\listlen\@findop[2]=1\relax
\itemtomacro\@findop[2]\tmpB
\else
\itemtomacro\@findop[2,2]\tmpD
\setsepchar{,}%
\readlist\tmpC{\tmpD}%
\def\tmpB{\tmpC}%
\fi
\if+\@findopsep[1]\relax
\def\tmp{\vecadd#1}%
\else\if-\@findopsep[1]\relax
\def\tmp{\vecsub#1}%
\else\if.\@findopsep[1]\relax
\def\tmp{\vecdot#1}%
\else\if x\@findopsep[1]\relax
\def\tmp{\veccross#1}%
\fi\fi\fi\fi
\expandafter\expandafter\expandafter\tmp\expandafter\tmpA\tmpB
}
\makeatother
\begin{document}
\readlist\A{1,2,3}
\readlist\B{4,5,6}
\vecadd\C\A\B
\C[]
VP:\vecparse\C{\A+\B}
\C[]
\vecsub\C\A\B
\C[]
VP:\vecparse\C{\A - \B}
\C[]
\vecdot\C\A\B
\C[]
VP:\vecparse\C{\A .\B}
\C[]
\veccross\C\A\B
\C[]
VP:\vecparse\C{\A x\B}
\C[]
VP:\vecparse\C{\A x(3,5,6)}
\C[]
VP:\vecparse\C{(3,5,6)x\B}
\C[]
VP:\vecparse\C{(1,1,1)x(1,2,3)}
\C[]
\end{document}
答案3
事实证明Henri Menke 提交允许检索符号坐标的原始坐标:有一个命令\coord
可以与calc
提供原始输入坐标的库一起使用。然后很容易添加一些解析这些坐标的函数。
\documentclass[tikz]{standalone}
\usetikzlibrary{calc}
\pgfmathdeclarefunction{xcomp3}{3}{% x component of a 3-vector
\begingroup%
\pgfmathparse{#1}%
\pgfmathsmuggle\pgfmathresult\endgroup}
\pgfmathdeclarefunction{ycomp3}{3}{% y component of a 3-vector
\begingroup%
\pgfmathparse{#2}%
\pgfmathsmuggle\pgfmathresult\endgroup}
\pgfmathdeclarefunction{zcomp3}{3}{% z component of a 3-vector
\begingroup%
\pgfmathparse{#3}%
\pgfmathsmuggle\pgfmathresult\endgroup}
\pgfmathdeclarefunction{veclen3}{3}{% 3d vector length
\begingroup%
\pgfmathparse{sqrt(pow(#1,2)+pow(#2,2)+pow(#3,2))}%
\pgfmathsmuggle\pgfmathresult\endgroup}
\newcommand{\spaux}[6]{(#1)*(#4)+(#2)*(#5)+(#3)*(#6)}
\pgfmathdeclarefunction{scalarproduct}{2}{% scalar product of two 3-vectors
\begingroup%
\pgfmathparse{\spaux#1#2}%
\pgfmathsmuggle\pgfmathresult\endgroup}
\newcommand{\vpauxx}[6]{(#2)*(#6)-(#3)*(#5)}
\newcommand{\vpauxy}[6]{(#4)*(#3)-(#1)*(#6)}
\newcommand{\vpauxz}[6]{(#1)*(#5)-(#2)*(#4)}
\pgfmathdeclarefunction{vpx}{2}{% x component of vector product
\begingroup%
\pgfmathparse{\vpauxx#1#2}%
\pgfmathsmuggle\pgfmathresult\endgroup}
\pgfmathdeclarefunction{vpy}{2}{% y component of vector product
\begingroup%
\pgfmathparse{\vpauxy#1#2}%
\pgfmathsmuggle\pgfmathresult\endgroup}
\pgfmathdeclarefunction{vpz}{2}{% z component of vector product
\begingroup%
\pgfmathparse{\vpauxz#1#2}%
\pgfmathsmuggle\pgfmathresult\endgroup}
\newcommand{\VP}[2]{% macro for vector product (not a function)
\pgfmathsetmacro\myx{vpx({#1},{#2})}%
\pgfmathsetmacro\myz{vpy({#1},{#2})}%
\pgfmathsetmacro\myy{vpz({#1},{#2})}%
(\myx,\myy,\myz)}
\begin{document}
\begin{tikzpicture}
\path (1,2,3) coordinate (a) (5,6,7) coordinate (b);
\path let \p1=(a),\p2=(b) in (0,-1)
node{$(a)=\coord1,(b)=\coord2,
\pgfmathsetmacro\myx{xcomp3\coord1}a_x=\myx,
\pgfmathsetmacro\myz{zcomp3\coord2}b_z=\myz,
\pgfmathsetmacro\myd{scalarproduct({\coord1},{\coord2})}
\vec a\cdot\vec b=\myd,%
\pgfmathsetmacro\myvpx{vpx({\coord1},{\coord2})}
\pgfmathsetmacro\myvpz{vpy({\coord1},{\coord2})}
\pgfmathsetmacro\myvpy{vpz({\coord1},{\coord2})}
\vec a\times\vec b=(\myvpx,\myvpy,\myvpz)=\VP{\coord1}{\coord2}
$};
\end{tikzpicture}
\end{document}
只要你在一个框架中工作,你就可以用一种简单的方式解析所有这些内容。然而,原始坐标不记得它们是在哪个框架中定义的。(请注意,还有命令\rawx
,\rawy
和\rawz
,其用途在下文中描述这里和这里。 他们是不是\coord
与以 3d 形式声明它们的三个条目相混淆。)
笔记:可以找到一些进一步的发展这里。它们允许您构建线性组合并计算 3d 中符号坐标的矢量积。