13

Is there a way to define a macro which would evaluate to the x part of the distance between two nodes? I know there are the point registers \p and the correspoding \x commands, but I find them rather cumbersome.

\documentclass{article}
\pagestyle{empty}
\usepackage{tikz}
\usetikzlibrary{positioning}

\newcommand{\xdist}[2]{%
  % Should compute a parseable representation of the
  % x part of the distance between two nodes
  1cm
}

\begin{document}
    \begin{tikzpicture}
        \node[rectangle,draw] (a) {a\strut};
        \node[rectangle,draw,below right=0.2cm of a] (b) {b\strut};
        \node[rectangle,draw,below=0.2cm of b.south east,
              anchor=north east,
              minimum width=\xdist{b.east}{a.west}] (ab) {ab\strut};
    \end{tikzpicture}
\end{document}

Result of compilation

In the above MWE, the \xdist command is supposed to compute the minimum width of the ab node, but the value is currently hard-coded.

I am looking for a better way of Creating a node fitting the horizontal width of two other nodes.

krlmlr
  • 12,530

2 Answers2

14

new version

The idea from percusse here can be applied in this case and the code is better.

 \documentclass{article}
 \pagestyle{empty}
 \usepackage{tikz}
 \usetikzlibrary{positioning}

 \makeatletter  
 \tikzset{minimum dist/.code 2 args={%
      \path (#1);
      \pgfgetlastxy{\xa}{\ya} 
       \path (#2);
      \pgfgetlastxy{\xb}{\yb}   
       \pgfpointdiff{\pgfpoint{\xa}{\ya}}%
                    {\pgfpoint{\xb}{\yb}}%
       \pgf@xa=\pgf@x}
    ,
   minimum width=\pgf@xa
   } 

 \begin{document}
     \begin{tikzpicture}
         \node[rectangle,draw] (a) {a\strut};
         \node[rectangle,draw,below right=2.2cm of a] (b) {b\strut};
         \node[rectangle,draw,below=0.2cm of b.south east,
               anchor=north east,minimum dist={a.west}{b.east}] (ab) {ab\strut};   
     \end{tikzpicture}
 \end{document} 

A macro is not a function ( mathematical term). When yo use minimum width you need to give a length. I'm not a great (TeX)pert but I think it's difficult to make exactly what you want (call a macro and get only the length).

A possibility

 \documentclass{article}
 \pagestyle{empty}
 \usepackage{tikz}
 \usetikzlibrary{positioning}

 \makeatletter  
 \tikzset{minimum dist/.style n args={4}{%
   insert path={% 
     \pgfextra{%
       \pgfpointdiff{\pgfpointanchor{#1}{#2}}%
                    {\pgfpointanchor{#3}{#4}}%
       \pgf@xa=\pgf@x}
       },
   minimum width=\pgf@xa}
  } 

 \begin{document}
     \begin{tikzpicture}
         \node[rectangle,draw] (a) {a\strut};
         \node[rectangle,draw,below right=2.2cm of a] (b) {b\strut};
         \node[rectangle,draw,below=0.2cm of b.south east,
               anchor=north east,minimum dist={a}{west}{b}{east}] (ab) {ab\strut};   
     \end{tikzpicture}
 \end{document}    

Update

A variant to use 2 arguments only.

 \documentclass{article}
 \pagestyle{empty}
 \usepackage{tikz}
 \usetikzlibrary{positioning}

 \makeatletter  
 \tikzset{minimum dist/.style 2 args={%
   insert path={% 
     \pgfextra{% 
      \path (#1);
      \pgfgetlastxy{\xa}{\ya} 
       \path (#2);
      \pgfgetlastxy{\xb}{\yb}   
      \pgfpointdiff{\pgfpoint{\xa}{\ya}}%
                    {\pgfpoint{\xb}{\yb}}%
      \pgf@xa=\pgf@x}
       },
   minimum width=\pgf@xa}
   } 

 \begin{document}
     \begin{tikzpicture}
         \node[rectangle,draw] (a) {a\strut};
         \node[rectangle,draw,below right=2.2cm of a] (b) {b\strut};
         \node[rectangle,draw,below=0.2cm of b.south east,
               anchor=north east,minimum dist={a.west}{b.east}] (ab) {ab\strut};   
     \end{tikzpicture}
 \end{document}

enter image description here

If you need to get the minimum height, the next code gives the two dimensions

\documentclass{article}
 \pagestyle{empty}
 \usepackage{tikz}
 \usetikzlibrary{positioning}

 \makeatletter
 \newdimen\y@min@dim 
  \newdimen\x@min@dim  
 \tikzset{h minimum dist/.code 2 args={%
      \path (#1);
      \pgfgetlastxy{\xa}{\ya} 
       \path (#2);
      \pgfgetlastxy{\xb}{\yb}   
       \pgfpointdiff{\pgfpoint{\xa}{\ya}}%
                    {\pgfpoint{\xb}{\yb}}%
       \y@min@dim=\pgf@y}
    ,
   minimum height=\y@min@dim
   } 
  \tikzset{w minimum dist/.code 2 args={%
       \path (#1);
       \pgfgetlastxy{\xa}{\ya} 
        \path (#2);
       \pgfgetlastxy{\xb}{\yb}   
        \pgfpointdiff{\pgfpoint{\xa}{\ya}}%
                     {\pgfpoint{\xb}{\yb}}%
        \x@min@dim=\pgf@x}
     ,
    minimum width=\x@min@dim
    } 
    \makeatother

 \begin{document}
     \begin{tikzpicture}
         \node[rectangle,draw] (a) {a\strut};
         \node[rectangle,draw,below right=2.2cm of a] (b) {b\strut};
         \node[rectangle,draw,below=0.2cm of b.south east,
               anchor=north east,
               w minimum dist={a.west}{b.east}] (hab) {h ab\strut}; 
        \node[rectangle,draw,right=0.2cm of b.south east,
              anchor=south west,
              h minimum dist={b.south}{a.north}
              ] (wab) {w ab\strut}; 

              \node[rectangle,draw=red, 
                    anchor=north west,
                    h minimum dist={b.south}{a.north},
                    w minimum dist={a.west}{b.east},
                    ] (test) at (a.north west) {test};  
     \end{tikzpicture}
 \end{document}

enter image description here

Alain Matthes
  • 95,075
  • Very beautiful solution. – Paul Gaborit Jul 19 '12 at 07:43
  • Thanks but it's not exactly what the OP wants but my english is not good enough to explain the confusion between function and macro and I don't know if we can use a trick to find a workaround. – Alain Matthes Jul 19 '12 at 07:52
  • @Altermundus: No, the solution is indeed beautiful. Is there a way to reduce it to two parameters so that I can pass a.west and b.east straight away? – krlmlr Jul 19 '12 at 07:55
  • Yes it's possible. With TeX and the same method, it's possible to find the node name and the anchor from a.west and it's possible with TikZ. I updated my code with a TikZ approach. – Alain Matthes Jul 19 '12 at 08:16
  • @PolGab not so beautiful, minimum dist/.code 2 args is better – Alain Matthes Jul 24 '12 at 07:08
  • @AlainMatthes How one needs to change your approach to calculate the minimum heightinstead of minimum width? (I tried it by changing the name of the macro and changing the last line of your macro as following but failed: \pgf@ya=\pgf@y} }, minimum height=\pgf@ya}) – John Mar 27 '13 at 14:18
  • @John I updated my answer for your request. Is it what you wanted? – Alain Matthes Mar 27 '13 at 14:57
  • @AlainMatthes Sorry, not quite: I would like to use both, w minimum dist and h minimum dist for a node at the same time, e.g. \node[rectangle,draw,left=0.2cm of wab.south east, anchor=south west,w minimum dist={a.west}{b.east},h minimum dist={b.south}{a.north}] (test) {test}; Depending on the order of your minimum dist-macros, the node will eventually be as wide as w minimum dist or as high as h minimum dist. – John Mar 27 '13 at 15:45
  • @John Yes I updated my code to avoid this problem. – Alain Matthes Mar 27 '13 at 16:14
  • @John I've a tex's problem to avoid the use of newdimen. It would be better to avoid the creation of dimen . – Alain Matthes Mar 27 '13 at 16:27
6

Edit: Here is a better solution via let operation:

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{positioning,calc}

\begin{document}
\begin{tikzpicture}
  \node[rectangle,draw] (a) {a\strut};
  \node[rectangle,draw,below right=0.2cm of a] (b) {b\strut};

  \path let \p{1}=(a.west), \p{2}=(b.east), \n{x dist}={abs(\x{2}-\x{1})} in
  node[rectangle,draw,below=0.2cm of b.south east,anchor=north east,minimum width=\n{x dist}]
  (ab) {ab\strut};
\end{tikzpicture}
\end{document}

First answer: Here is your example modified to use \setxveclength:

\documentclass{article}
\pagestyle{empty}
\usepackage{tikz}
\usetikzlibrary{positioning}

\makeatletter
\newcommand\setxveclength[5]{% newmacro, node1, anchor1, node2, anchor2
  \pgfpointdiff{\pgfpointanchor{#2}{#3}}{\pgfpointanchor{#4}{#5}}
  \edef#1{\the\pgf@x}
}
\makeatother

\begin{document}
    \begin{tikzpicture}
        \node[rectangle,draw] (a) {a\strut};
        \node[rectangle,draw,below right=0.2cm of a] (b) {b\strut};
        \setxveclength{\mydist}{a}{west}{b}{east}
        \node[rectangle,draw,below=0.2cm of b.south east,
              anchor=north east,
              minimum width=\mydist] (ab) {ab\strut};
    \end{tikzpicture}
\end{document}

enter image description here

Paul Gaborit
  • 70,770
  • 10
  • 176
  • 283
  • 1
    Nice, but not quite what I was looking for. Is there a way to stick to the interface I am suggesting (two arguments, returning the length rather than setting a length with it)? And if not, why? – krlmlr Jul 18 '12 at 23:40
  • 1
    \pgfpointdiff is enough to get the xand y of a vector. – Alain Matthes Jul 19 '12 at 07:25
  • @Altermundus Yes! I change my answer to use \pgfpointdiff. – Paul Gaborit Jul 19 '12 at 07:39
  • 1
    A little shortcut is using \edef#1{\the\pgf@x} directly after pgfpointdiff but then we need to have makeatletter ... makeatother so not much of a shortcut :) – percusse Jul 19 '12 at 08:11
  • @percusse: it's a good shortcut. This avoids the use of two arbitrary macro names (\xa and \ya). So, a new edition... – Paul Gaborit Jul 19 '12 at 08:32