47

Given two points (defined, for instance using nodes), I want to compute the distance between them.

  1. Is there some build in functionality in tikz to do this?
  2. If not, how can it be done using the mathematical engine?

The application I have in mind is to draw an circular arc centered at (a) and passing through some second point (b), where only (a) and (b) are known.

Stefan Kottwitz
  • 231,401
Dror
  • 22,613
  • Have a look at the through library for this purpose. – Roelof Spijker Dec 16 '11 at 11:29
  • 4
    What about veclen(a,b)? – Ignasi Dec 16 '11 at 11:46
  • @Ignasi I would use the typical computationsqrt((vx)^2+(vy)^2) instead of veclen(vx,vy) (see my answer below). veclen has a quite low precision. For example for (vx,vy)=(10,10), the real norm value is 14.142135623.... For veclen we get 14.14154 while sqrt((vx)^2+(vy)^2) yields 14.14213. Such an error can make a difference for certain purposes. – loved.by.Jesus Jun 29 '21 at 11:54

3 Answers3

32

With TikZ, you have the answer with percusse, with pgfmath is the same method but you need to determine the coordinates vx, vy of the vector formed by the two points and then \pgfmathparse{veclen(vx,vy)} the result is in \pgfmathresult.

Personally, I take a few fantasies with the TikZ's syntax. I do not find very satisfactory the syntax let \p1 \n1 and I prefer to calculate the length before drawing the objects. In addition, in some cases the result is not very fine also I use fp to calculate the length. Lua is also a possibilty. It's also possible to use the library fpu with TikZ.

\documentclass[11pt]{scrartcl}
\usepackage{tikz,fp}
\usetikzlibrary{calc}

\makeatletter
\def\calcLength(#1,#2)#3{%
\pgfpointdiff{\pgfpointanchor{#1}{center}}%
             {\pgfpointanchor{#2}{center}}%
\pgf@xa=\pgf@x%
\pgf@ya=\pgf@y%
\FPeval\@temp@a{\pgfmath@tonumber{\pgf@xa}}%
\FPeval\@temp@b{\pgfmath@tonumber{\pgf@ya}}%
\FPeval\@temp@sum{(\@temp@a*\@temp@a+\@temp@b*\@temp@b)}%
\FProot{\FPMathLen}{\@temp@sum}{2}%
\FPround\FPMathLen\FPMathLen5\relax
\global\expandafter\edef\csname #3\endcsname{\FPMathLen}
}
\makeatother

\begin{document} 

  5cm = 5*28.45274 pt =142.2637pt

\begin{tikzpicture}
\coordinate (A) at (1,2);
\coordinate (B) at (4,6);
\calcLength(A,B){mylen}
% \draw (A) circle (\mylen pt); % pt is important here
\end{tikzpicture}
With calclength the length of AB is : \mylen

\begin{tikzpicture}
\coordinate (A) at (1,2);
\coordinate (B) at (4,6);
\path (A) let   \p1 = ($ (B) - (A) $),  \n1 = {veclen(\x1,\y1)} 
    in -- (B) node[draw]  {With veclen the length is :\n1};
\end{tikzpicture}   

\end{document}

enter image description here

to get the arc the code is

\calcLength(A,B){mylen} 
\draw[red,line width=1mm]  (A) -- ++(45:\mylen pt);  
\draw[blue] (A) -- ++(\mylen pt,0) arc (0:45:\mylen pt); 

For me it is more readable but it is a matter of taste

Alain Matthes
  • 95,075
30

As wh1t3 commented, there is a through library which even has the command circle through. Here is the example in the manual: After adding the line \usetikzlibrary{through} in the preamble,

\begin{tikzpicture}
\draw[help lines] (0,0) grid (3,2);
\node (a) at (2,1.5) {$a$};
\node [draw] at (1,1) [circle through={(a)}] {$c$};
\end{tikzpicture}

You can do this using the calc library with almost the same convenience (on which Ignasi commented while I was typing the answer). You can further use this for other purposes: Modfying the example slightly and using \usetikzlibrary{calc} in the preamble, you can get the vector length by using the veclen command as

\begin{tikzpicture}
\coordinate [label=left:$A$] (A) at (0,0);
\coordinate [label=right:$B$] (B) at (2,2);

\draw[red,line width=1mm] let \p1 = ($(B)-(A)$) in (A) -- ++(45:({veclen(\x1,\y1)}););
\draw (A) -- (B);
\draw[blue] (A) let \p1 = ($(B)-(A)$) in -- ++({veclen(\x1,\y1)},0) arc (0:45:({veclen(\x1,\y1)}););
\end{tikzpicture}

which would give

enter image description here

percusse
  • 157,807
17

With the TikZ library math looks quite intuitive :)

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{math}

\begin{document} \begin{tikzpicture} %Two points (A) and (B) \coordinate (A) at (0,0); \coordinate (B) at (2,2);

%--Computing the distance between (A) and (B) %Creating a math coordinate \tikzmath{coordinate \C; %Storing coordinates difference \C = (B)-(A); %Computing the length of C = (Cx,Cy) from its components Cx and Cy %Note the length \distAB is in points (pt) \distAB = sqrt((\Cx)^2+(\Cy)^2); }

%--Drawing %line A -- B \draw (A) node [above] {A} -- (B) node[above] {B} node[midway]{\distAB pt}; %Circle with center in (A) and radius \distAB points \draw (A) circle (\distAB pt); \end{tikzpicture}

\end{document}

Note: instead of manually computing the norm \distAB = sqrt((\Cx)^2+(\Cy)^2);, you will see in the math TikZ library the function veclen(Vx,Vy). I discourage its use, because the precision is disappointingly low.

enter image description here

Additional solution in cm

It is quite bewildering that TikZ points accept per default lengths in cm (e.g., \coordinate (A) at (2,2) means (2cm,2cm)), but calculations of coordinates in tikzmath are performed and output in pt. For that reason, I have carried out tiny modifications in the code above so that all lengths are consistently represented in cm. (Credits for the \convertto macro go to Philippe Goutet)

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{math}

\makeatletter \def\convertto#1#2{\strip@pt\dimexpr #2*65536/\number\dimexpr 1#1} \makeatother

\begin{document} \begin{tikzpicture} %Two points (A) and (B) %Note: Default TikZ coordinates are centimeters % but inner computations are performed in pt \coordinate (A) at (0,0); \coordinate (B) at (2,2);

%--Computing the distance between (A) and (B) %Creating a math coordinate \tikzmath{coordinate \C; %Storing coordinates difference \C = (B)-(A); %Computing the length of C = (Cx,Cy) from its components Cx and Cy %Note the length \distAB is in points (pt) \distAB = sqrt((\Cx)^2+(\Cy)^2); %Convert back to centimeters \distAB = \convertto{cm}{\distAB pt}; }

%--Drawing %line A -- B \draw (A) node [above] {A} -- (B) node[above] {B} node[midway]{\distAB cm}; %Circle with center in (A) and radius \distAB cm %Note that we need not specify (\distAB cm) because %the standard length unit in TikZ drawing is centimeter \draw (A) circle (\distAB); \end{tikzpicture}

\end{document}

enter image description here