TikZ: Get (dimensionless) distance between node anchors
I think I've got it, though perhaps there are other solutions, hopefully more efficient; it requires the math
library.
\documentclass[
tikz
]{standalone}
\usepackage[T1]{fontenc}
\usetikzlibrary{
calc,
positioning,
math
}
\begin{document}
\begin{tikzpicture}[font = {\fontsize{40}{42}\selectfont}]
\node[draw, blue] (A) at (0,0) {NODE A};
\node[draw, red, anchor = north] (B) at (A.mid west) {NODE B};
\draw (A.north east) -- node[midway, sloped, anchor = south, inner sep = 0, fill = gray, opacity = 0.6] {\normalsize\bfseries This length} (B.south west);
\node[draw, anchor = north east] (C) at (B.south west) {NODE C};
\coordinate[above = 2.7pt of C.north west] (uno) {};
\coordinate[above = 2.7pt of C.north east] (dos) {};
\draw[densely dashed] (uno) -- (dos) node [midway, solid] {\normalsize This length};
% \draw let \p1 = ($ (B.south west) - (A.north east) $), \n1 = {veclen(\x1,\y1)}
% in circle [at = (C.center), radius =\n1];
\tikzmath{
coordinate \p;
\p = (B.south west) - (A.north east);
\len = veclen(\p);
\lencm = 0.035*\len;
}
\node[minimum width = {\lencm cm}, draw, purple, fill = gray!10, opacity = 0.5] (D) at (C.center) {NODE D};
\draw (C.north east) circle (\len pt);
\draw (D.west) circle (\lencm);
\node[circle, inner sep = 1pt, fill] at (D.west) {};
\end{tikzpicture}
\end{document}
I also defined the same length in centimetres multiplying by the appropriate factor; I noticed, however, that I must type minimum length = {\lencm cm}
to get a rectangle of the appropriate size; otherwise I get a node exactly the size of C; the unit specification is unnecessary when drawing the circle, though. Does anyone know why?
In this case you can use the path to draw all objects you use. In order to convert \n1
to a dimensionless number \mylen
such that \mylen cm=\n1
you can use
\pgfextra{\pgfmathsetmacro{\mylen}{\n1/1cm}}
In this example this is not necessary, i.e. you can use \n1
for all the lengths, but here is an example.
\documentclass[tikz]{standalone}
\usepackage[T1]{fontenc}
\usetikzlibrary{
calc,
positioning
}
\begin{document}
\begin{tikzpicture}[font = {\fontsize{40}{42}\selectfont}]
\node[draw, blue] (A) at (0,0) {NODE A};
\node[draw, red, anchor = north] (B) at (A.mid west) {NODE B};
\draw (A.north east) -- node[midway, sloped, anchor = south, inner sep = 0, fill = gray, opacity = 0.6] {\normalsize\bfseries This length} (B.south west);
\node[draw, anchor = north east] (C) at (B.south west) {NODE C};
\coordinate[above = 2.7pt of C.north west] (uno) {};
\coordinate[above = 2.7pt of C.north east] (dos) {};
\draw[densely dashed] (uno) -- (dos)
node [midway, solid] {\normalsize This length};
\draw let \p1 = ($ (B.south west) - (A.north east) $), \n1 = {veclen(\x1,\y1)}
in \pgfextra{\pgfmathsetmacro{\mylen}{\n1/1cm}}
node[minimum width =\n1, draw, purple, fill = gray!10,
opacity = 0.5] (D) at (C.center) {NODE D}
(C.north east) circle [radius =\mylen]
(D.west) circle [radius=\mylen];
\draw[red,dashed,thick] let \p1 = ($ (B.south west) - (A.north east) $), \n1 = {veclen(\x1,\y1)}
in \pgfextra{\pgfmathsetmacro{\mylen}{\n1/1cm}}
(C.north east) circle [radius =\n1]
(D.west) circle [radius=\n1];
\end{tikzpicture}
\end{document}
As you can see, the circles match, i.e. the dashed red circles of radius \n1
are on top of the circles of radius \mylen
. This is sort of an accident, though, since in principle TikZ distinguishes between radii, i.e. dimensionful quantities, and dimensionless radius factors, see here for a nice discussion. In the case at hand, the unit vectors have the length 1cm
, which is why the results match. That is, a dimensionless radius is interpreted as (radius factor) * (length of unit vector)
. This means in particular that if the x and y unit vectors have different lengths, you will get an ellipse with the dimensionless radius.
ADDENDUM: Here are some comments on smuggling, i.e. the question about broadcasting a macro out of a group without making it global. This is relevant for paths and for foreach
loops, for example. Smuggling has been discussed here. Henri Menke has kindly added this answer, which will be fully working in the next version of pgf (now one has to use it with a small fix). These tricks have not yet been appreciated as much as they could That is, if you use version 3.1.6 or higher, you won't need the fix. The core level macros \pgfutil@pushmacro
and \pgfutil@popmacro
can be built in pgf functions that allow us to smuggle. Here is an example.
\documentclass[tikz]{standalone}
\usetikzlibrary{calc,positioning}
\makeatletter
% using https://tex.stackexchange.com/a/491246/194703
% won't be needed in future versions of tikz/pgf
% see fix https://github.com/pgf-tikz/pgf/commit/0034290cb0295bafbb45f27a12a71a67797fcdbb
\def\pgfutil@pushmacro#1{%
\xdef\pgfutil@pushmacro@string{\string#1}%
\ifcsname pgfutil@pushedmacro@\pgfutil@pushmacro@string\endcsname\else
% \newcount is \outer in Plain
\csname newcount\expandafter\endcsname\csname pgfutil@pushedmacro@\pgfutil@pushmacro@string\endcsname
\fi
\global\advance\csname pgfutil@pushedmacro@\pgfutil@pushmacro@string\endcsname 1\relax
\global\expandafter\let\csname\the\csname pgfutil@pushedmacro@\pgfutil@pushmacro@string\endcsname\pgfutil@pushmacro@string\endcsname#1%
}
\tikzset{push/.code={\expandafter\edef\csname#1\endcsname{\csname#1\endcsname}%
\expandafter\pgfutil@pushmacro\csname#1\endcsname}}
\pgfmathdeclarefunction{pop}{1}{\begingroup
\expandafter\pgfutil@popmacro\csname#1\endcsname%
\expandafter\pgfmathparse\expandafter{\csname#1\endcsname}%
\pgfmathsmuggle\pgfmathresult
\endgroup}
\makeatother
\begin{document}
\begin{tikzpicture}
\node[draw, blue] (A) at (0,0) {NODE A};
\node[draw, red, anchor = north] (B) at (A.mid west) {NODE B};
\draw let \p1 = ($ (B.south west) - (A.north east) $), \n1 = {veclen(\x1,\y1)}
in \pgfextra{\pgfmathsetmacro{\mylen}{\n1/1cm}}
[push={mylen}];
\path (A)
node[above=1ex]{length in cm is $\pgfmathparse{pop("mylen")}\pgfmathprintnumber\pgfmathresult$};
\foreach \X [count=\Y] in {A,...,F}
{\edef\mycount{\Y}
\tikzset{push=mycount}}
\pgfmathparse{pop("mycount")}
\typeout{\pgfmathresult}
\end{tikzpicture}
\end{document}
As you can see, you can now use
\tikzset{push=mycount}}
to push the macro \mycount
and then use the pgf function pop("mycount")
to retrieve its value outside of the group. pop("mycount")
can be used in any expression that gets parsed by TikZ, including coordinates. Similar tricks allow one to keys in foreach
of the type remember outside
. That is, one of the biggest drawbacks of the \foreach
loop can be overcome with Henri's answer.