如何在 pgf/tikz 中规范化向量?

如何在 pgf/tikz 中规范化向量?

我在 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为当前坐标系。这样做的好处是,坐标系中的任何变化(可以使用xy键来更改坐标系)标准化向量的长度仍然为1(而不是1cm在其他答案中使用的纸平面)。

    但是,该键也可以用于设置然后使用的固定长度(在纸平面中)。

在不改变坐标系的情况下,Norm=1使用示例 1 的 默认值

实施例1a

x={(1.5cm,1cm)},
y={(-1.5cm,1cm)}

我们得到

示例 1b

代替 (Norm=1cm

示例 1c

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}

在此处输入图片描述

相关内容