我在 pgf/tikz 中绘制了一幅图,其中我在开始时定义了一些向量(坐标)。图片根据这些初始坐标位置而变化。例如:\坐标 (A) 在 (3,4);
在绘图过程中,我需要对这些向量进行归一化。如何计算 A 的归一化版本的对应向量?
答案1
使用以下语法的可能性如下()!<length>!()
:
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc,arrows}
\newcommand\normalize[2][(0,0)]{%
\draw[red,->] #1 -- ($#1!1cm!#2$);}
\begin{document}
\begin{tikzpicture}[>=latex]
\coordinate (a) at (1,3);
\coordinate (b) at (-2,5);
\coordinate (c) at (-0.5,0-.5);
\draw[->,ultra thin] (0,0) -- (b);
\draw[->,ultra thin] (0,0) -- (a);
\draw[->,ultra thin] (a) -- (b);
\normalize{(a)};
\normalize{(b)};
\normalize{($(b)-(a)$)};
\normalize[(a)]{(b)};
\end{tikzpicture}
\end{document}
\normalize
有一个必需参数和一个可选参数。将从原点\normalize{(x)}
绘制对应于 的标准向量。是从到 的路径;即从 开始并沿着从到方向行进的路径。(x)
\normalize[(y)]{(x)}
(y)
(y)!1cm!(x)
(y)
1cm
(y)
(x)
为了可视化目的,原始向量被画得很细,并且其标准化版本为红色。
答案2
这是一个带有 的解决方案to path
。第一个参数是偏移的长度。默认为 1cm。
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc}
\tikzset{offset/.style={to path={%
-- ($(\tikztostart)!#1cm!(\tikztotarget)$)}},
offset/.default=1}
\begin{document}
\begin{tikzpicture}
\draw[help lines] (0,0) grid (3,3);
\draw[red,->] (0,0) to[offset=2] (100,0);
\draw[blue,->] (0,0) to[offset] (0,2);
\draw[->] (1,1) to[offset=1.5] (1,2);
\end{tikzpicture}
\end{document}
答案3
我决定创建一个自定义坐标系,norm cs:
所需的宏和两个键都打包在库中norm
(→ \usetikzlibrary{norm}
)。
键:
norm
是一个to path
(类似于其他答案中已经讨论过的)它使用norm cs
来创建一个规范化向量。Norm
可用于改变标准化向量的长度。默认
1
为当前坐标系。这样做的好处是,坐标系中的任何变化(可以使用x
和y
键来更改坐标系)标准化向量的长度仍然为1
(而不是1cm
在其他答案中使用的纸平面)。但是,该键也可以用于设置然后使用的固定长度(在纸平面中)。
在不改变坐标系的情况下,Norm=1
使用示例 1 的 默认值
和
x={(1.5cm,1cm)},
y={(-1.5cm,1cm)}
我们得到
代替 (Norm=1cm
)
norm cs:
接受任何 TikZ和一个可选的norm cs
参数(默认情况下为原点)。这将产生标准化(根据设置)向量。<coordinate>
from <another coordinate>
<another coordinate>
(0,0)
Norm
请注意,这不会绘制与路径上的当前点相关的任何线。
\draw (1,2) -- (norm cs: 3,0);
将导致一条从(1,2)
到 的线(1,0)
,而不是(情况 A)也不是从到 的(2,2)
点(情况 B)。最有可能与相对坐标一起使用。以下将绘制一条从到 的线(情况 A):1cm
(1,2)
(3,0)
norm cs
(1,2)
(2,2)
\draw (1,2) -- ++(norm cs: 3,0);
如果要指定1cm
从(1,2)
到 的点(33,0)
,则需要使用from
参数
\draw (1,2) -- ++(norm cs: 3,0 from 1,2);
或者norm
to path
:
\draw (1,2) to[norm] (3,0);
代码
tikzlibrarynorm.code.tex
\tikzset{
Norm/.code={%
\pgfmathparse{#1}%
\edef\qrr@tikz@norm{\pgfmathresult\ifpgfmathunitsdeclared pt\fi}%
\let\ifqrr@tikz@normcs@unitsdeclared\ifpgfmathunitsdeclared},
Norm=1,
norm/.style={to path={-- ++(norm cs: \tikztotarget\space from \tikztostart)}}
}
\newif\ifqrr@tikz@normcs@unitsdeclared
\newdimen\qrr@pgf@normcs@from@x\newdimen\qrr@pgf@normcs@from@y
\tikzdeclarecoordinatesystem{norm}{%
\let\qrr@next\relax
\pgfutil@in@{ from }{#1}%
\ifpgfutil@in@
\qrr@tikz@normcs@parse@from#1\@qrr@tikz@normcs@parse@from
\let\qrr@next\qrr@tikz@normcs@calc@hard
\else
\qrr@tikz@normcs@parse@from#1 from +0pt,+0pt\@qrr@tikz@normcs@parse@from
\fi
\expandafter\qrr@tikz@normcs@parse@@to\expandafter{\qrr@tikz@normcs@parse@to}%
}
\def\qrr@tikz@normcs@calc@easy#1{%
\pgf@xx\@ne
\pgf@yy\@ne
\pgf@xy\z@
\pgf@yx\z@
\tikz@scan@one@point\pgfutil@firstofone(#1)\relax
\pgfmathatantwo{+\pgf@x}{+\pgf@y}%
}
\def\qrr@tikz@normcs@calc@hard#1{%
\tikz@scan@one@point\pgfutil@firstofone(#1)\relax
\pgf@xa\pgf@x\pgf@ya\pgf@y
\advance\pgf@xa-\qrr@pgf@normcs@from@x
\advance\pgf@ya-\qrr@pgf@normcs@from@y
\pgfpointnormalised{\pgfqpoint{\pgf@xa}{\pgf@ya}}
\pgfmathsetlength\pgf@xa{\pgf@yy*\pgf@x-\pgf@yx*\pgf@y}
\pgfmathsetlength\pgf@ya{-\pgf@xy*\pgf@x+\pgf@xx*\pgf@y}
\pgfmathatantwo{+\pgf@xa}{+\pgf@ya}
}
\def\qrr@tikz@normcs@calc@unit#1{%
\tikz@scan@one@point\pgfutil@firstofone(#1)\relax
\pgf@xa\pgf@x\pgf@ya\pgf@y
\advance\pgf@xa-\qrr@pgf@normcs@from@x
\advance\pgf@ya-\qrr@pgf@normcs@from@y
\pgfpointnormalised{\pgfqpoint{\pgf@xa}{\pgf@ya}}
\pgfmathatantwo{+\pgf@x}{+\pgf@y}
}
\def\qrr@tikz@normcs@parse@@to#1{%
\ifqrr@tikz@normcs@unitsdeclared
\let\qrr@next\qrr@tikz@normcs@calc@unit
\else
\ifx\qrr@next\relax
\pgfutil@in@{cs:}{#1}%
\ifpgfutil@in@
\let\qrr@next\qrr@tikz@normcs@calc@hard
\else
\pgfutil@in@{intersection }{#1}%
\ifpgfutil@in@
\let\qrr@next\qrr@tikz@normcs@calc@hard
\else
\pgfutil@in@|{#1}%
\ifpgfutil@in@
\let\qrr@next\qrr@tikz@normcs@calc@hard
\else
\pgfutil@in@:{#1}%
\ifpgfutil@in@
\let\qrr@next\qrr@tikz@normcs@calc@easy
\else
\pgfutil@in@,{#1}%
\ifpgfutil@in@
\let\qrr@next\qrr@tikz@normcs@calc@easy
\else
\let\qrr@next\qrr@tikz@normcs@calc@hard
\fi
\fi
\fi
\fi
\fi
\fi
\fi
\begingroup
\qrr@next{#1}%
\pgfmath@smuggleone\pgfmathresult
\endgroup
\let\pgf@tempa\pgfmathresult
% \pgfmathifthenelse{\pgf@tempa<0}{\pgf@tempa+180}{\pgf@tempa}%
% \let\pgf@tempa\pgfmathresult
\ifqrr@tikz@normcs@unitsdeclared
\pgfpointpolar{\pgf@tempa}{\qrr@tikz@norm}%
\else
\pgfpointpolarxy{\pgf@tempa}{\qrr@tikz@norm}%
\fi
}
\def\qrr@tikz@normcs@parse@from#1 from #2\@qrr@tikz@normcs@parse@from{%
\def\qrr@tikz@normcs@parse@to{#1}%
\tikz@scan@one@point\pgfutil@firstofone(#2)\relax
\qrr@pgf@normcs@from@x\pgf@x
\qrr@pgf@normcs@from@y\pgf@y
}
示例 1
\documentclass[tikz]{standalone}
\usetikzlibrary{backgrounds,norm}
\begin{document}
\begin{tikzpicture}[
gridded,
% Norm=1cm,
% x=-2cm,
% x={(1.5cm,1cm)},
% y={(-1.5cm,1cm)}
]
\draw (0,0) coordinate[label=below:$O$] (O) circle (1);
\draw (1,3) coordinate[label=right:$a$] (a) circle (1);
\draw (-2,5) coordinate[label=left:$b$] (b) circle (1);
\draw (O) -- (b);\draw (O) -- (a);\draw (a) -- (b);
\tikzset{every path/.append style={green,thick}}
\path[->] (O) edge ++(norm cs: b)
edge ++(norm cs: a)
;
\path[->] (a) edge[blue] ++(norm cs: b)
edge[red] ++(norm cs: a)
edge[norm] (b) % equal to edge ++(norm cs: b from a)
edge ++(norm cs: O from a)
;
\path[->] (b) edge[red] ++(norm cs: b)
edge[blue] ++(norm cs: a)
edge ++(norm cs: a from b)
edge ++(norm cs: O from b)
;
\end{tikzpicture}
\end{document}
答案4
这是一种无需计算的方法。我曾经\pgfpointnormalised
得到一个宽度为 1pt 的矢量。
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{arrows}
\makeatletter
\def\vectornormalised#1#2{%
\begingroup
\coordinate (tempa) at (#1);
\coordinate (tempb) at (#2);
\pgfpointdiff{\pgfpointanchor{tempa}{center}}%
{\pgfpointanchor{tempb}{center}}%
\pgfpointnormalised{}
\pgf@xa=28.45274\pgf@x%
\pgf@ya=28.45274\pgf@y%
\draw[red,->] (#1)-- +(\the\pgf@xa,\the\pgf@ya) coordinate (tempc);
\endgroup
}
\tikzset{norm/.style={to path={%
\pgfextra{\vectornormalised{\tikztostart}{\tikztotarget}} (tempc) -- (\tikztotarget) \tikztonodes
}}}
\makeatother
\begin{document}
\begin{tikzpicture}[>=latex]
\draw[help lines] (0,0) grid (5,3);
\coordinate (a) at (1,0);
\coordinate (b) at (5,1);
\coordinate (c) at (2,3);
\draw[blue,->] (a) to [norm] (b);
\draw[orange,->] (b) to[norm] (c);
\draw[green,->] (a) to [norm] (c);
\draw (a) circle (1cm);
\end{tikzpicture}
\end{document}