9

Suppose I have a coordinate in tikz 3d which I interpret as a vector, for example

\coordinate (v) at (3,2,9);

What's the best way to get the unit vector pointing into the same direction?

My first idea was to use the let syntax, but this doesn't work in 3d.

For example

\path let \p1 = (v) in ($1/(x1^2 + x2^2 + x3^3)^(0.5)*(v)$) coordinate (vv);

Anyhow I am looking for a more easy to use solution than using let for this...

student
  • 29,003

1 Answers1

8

How about this:

Code

\documentclass[parskip]{scrartcl}
\usepackage[margin=15mm]{geometry}
\usepackage{tikz}
\usetikzlibrary{arrows,calc}

\newcommand{\unitvec}[3][->]% [options], start point, vector
{   \xdef\mysum{0}
    \foreach \c in  {#3}
    {   \pgfmathsetmacro{\mysquare}{\mysum+pow(\c,2)}
        \xdef\mysum{\mysquare}
    }
    \pgfmathsetmacro{\myveclen}{sqrt(\mysum)}
    \draw[#1] (#2) -- ($1/\myveclen*(#3)$);
}

\begin{document}

\begin{tikzpicture}
\draw[-latex] (0,0,0) -- (3,6,2);
\unitvec[-latex,red,thick]{0,0,0}{3,6,2}

\draw[->] (0,0,0) -- (-2,4,3);
\unitvec[->,blue,thick]{0,0,0}{-2,4,3}

\draw[-stealth] (0,0,0) -- (-1,-4,-1);
\unitvec[-stealth,green,thick]{0,0,0}{-1,-4,-1}
\end{tikzpicture}

\end{document}

Output

enter image description here


Edit 1: Here's a version with a new \Coordinate(<name>)(<vector>). To work it now needs \Unitvec, as \unitvec only works with direct numbers.

Code

\documentclass[parskip]{scrartcl}
\usepackage[margin=15mm]{geometry}
\usepackage{tikz}
\usetikzlibrary{arrows,calc}

\def\Coordinate(#1)(#2)% name, vector
{   \expandafter\xdef\csname#1\endcsname{#2}
    \coordinate (#1) at (#2);
}

% for use with \Coordinates
\newcommand{\Unitvec}[3][->]% [options], start point, vector
{   \xdef\mysum{0}
    \foreach \myconstant [count=\mycount] in    #3
    {   \pgfmathsetmacro{\mysquare}{\mysum+pow(\myconstant,2)}
        \xdef\mysum{\mysquare}
    }
    \pgfmathsetmacro{\myveclen}{sqrt(\mysum)}
    \draw[#1] (#2) -- ($1/\myveclen*(#3)$);
}

%for use with direct numbers, e.g. \unitvec[-latex,red,thick]{0,0,0}{3,6,2}
\newcommand{\unitvec}[3][->]% [options], start point, vector
{   \xdef\mysum{0}
    \foreach \c in  {#3}
    {   \pgfmathsetmacro{\mysquare}{\mysum+pow(\c,2)}
        \xdef\mysum{\mysquare}
    }
    \pgfmathsetmacro{\myveclen}{sqrt(\mysum)}
    \draw[#1] (#2) -- ($1/\myveclen*(#3)$);
}

\begin{document}

\begin{tikzpicture}
\Coordinate(o)(0,0,0)
\Coordinate(a)(3,6,2)
\Coordinate(b)(-2,4,3)
\Coordinate(c)(-1,-4,-1)

\draw[-latex] (o) -- (a);
\Unitvec[-latex,red,thick]{\o}{\a}

\draw[->] (o) -- (b);
\Unitvec[->,blue,thick]{\o}{\b}

\draw[-stealth] (o) -- (c);
\Unitvec[-stealth,green,thick]{\o}{\c}

\end{tikzpicture}

\end{document}

Output

Ecactly the same as before.

Please note:

\Coordinate uses \xdef to store the vectors, so it will overwrite existing commands without hesitation. Furthermore, it uses commands, so you'll have to write \a instead of a. It also creates a regular \coordinate. If you just need the point on the canvas, you can use a (as in the \draw commands), if the true 3D position matters, you should use \a (like for \unitvec). Also, using things like - or 8 in a coordinate name, which works in TikZ does not work with edef, so only use letters.

Tom Bombadil
  • 40,123
  • The \unitvec macro should take something like (v) as argument. – student Oct 09 '12 at 11:19
  • Then you have a problem, as Tikz internally uses only 2D coordinates. In this question, Andrew Stacey discusses a possible way around this using some experimental code. – Tom Bombadil Oct 09 '12 at 11:22
  • 1
    Even though the coordinate is given with 3D entries if you place a temporary coordinate at the tip, it's saved as a 2D coordinate so you can get the angle via atan2 and use (angle:1) to draw. – percusse Oct 09 '12 at 12:43
  • @percusse I don't really understand what you mean. – student Oct 09 '12 at 12:51
  • 1
    @percusse: Nice idea, but due to perspective the (canvas) length of a unit vector is not neccessarily equal one. Probably ($1/<veclen>*(<vec>)$) will work. – Tom Bombadil Oct 09 '12 at 13:27
  • 3
    @student 3D library of TikZ accepts 3D inputs but converts them (or projects them) onto the 2D plane. Hence if you put a coordinate at the tip of the line that is drawn using 3D point input, it would still be a 2D point. So that would give the direction that unit vector points to. Example: \begin{tikzpicture} \draw[ultra thick] (0,0,0) -- (1,1,1) coordinate (a); \draw[yellow] (0,0) -- (a); \end{tikzpicture}. Then you can say for example, \draw[blue,thick] (0,0) -- ($(0,0)!1cm!(a)$); to go 1cm along that direction. But as Tom mentioned this might not necessarily be 1cm. – percusse Oct 09 '12 at 16:34
  • @tom-bombadil I know it's quite an old subject but anyway, I can't get it working outside of origin. In fact you need to subtract starting point coords from those of the end point. And thus the \unitvec macro wont work outside of (0,0,0). I tried with a shifted scope but then it seems the points aren't shifted due to the \xdef in the definition \Coordinate (I guess...). BTW, wouldn't it be easier to use \draw[#1] (#2) -- ($(#2)!1/\myveclen!(#3)$); (again, in case the starting point is outside the origin...) – Vser Jul 23 '13 at 15:18