1

I am a beginner in LaTeX and I have a problem with the use of macros.

Let's say that I have created a macro that draws rectangles.

\documentclass[10pt,a4paper, landscape]{book}
\usepackage{tikz}
\usepackage[french]{babel}


\begin{document}

\newcommand\rect[4]{
\draw (#1,#2) rectangle (#3,#4);}

 \begin{tikzpicture}    
\rect{1}{2}{3}{4};   
\end{tikzpicture}       

\end{document}

It works. Now I would like to create a macro that join the first vertices of two rectangles. I searched on the Internet and found a way to gets the coordinate of the first vertex of a rectangle.

\documentclass[10pt,a4paper, landscape]{book}
\usepackage{tikz}
\usepackage[french]{babel}     

\begin{document}    

\def\generatex#1#2{%
  \begingroup
  \toks0={#2}%
  \edef\next{\def\expandafter\noexpand\csname varx#1\endcsname{\the\toks0 }}%
  \expandafter\endgroup\next}

\def\generatey#1#2{%
  \begingroup
  \toks0={#2}%
  \edef\next{\def\expandafter\noexpand\csname vary#1\endcsname{\the\toks0 }}%
  \expandafter\endgroup\next}    

\newcommand\rect[5]{
\draw (#1,#2) rectangle (#3,#4);
\generatex{#5}{#1};
\generatey{#5}{#2};}

\begin{tikzpicture}

\rect{1}{2}{3}{4}{rectone};
\rect{10}{5}{2}{3}{recttwo};
\draw(\varxrectone,\varyrectone)--(\varxrecttwo,\varyrecttwo);    

\end{tikzpicture}

\end{document}

This works again. But, let's say that I would like to define a general macro doing this. I tried the following but it doesn't work :

\documentclass[10pt,a4paper, landscape]{book}
\usepackage{tikz}
\usepackage[french]{babel}     

\begin{document}    

\def\generatex#1#2{%
  \begingroup
  \toks0={#2}%
  \edef\next{\def\expandafter\noexpand\csname varx#1\endcsname{\the\toks0 }}%
  \expandafter\endgroup\next}

\def\generatey#1#2{%
  \begingroup
  \toks0={#2}%
  \edef\next{\def\expandafter\noexpand\csname vary#1\endcsname{\the\toks0 }}%
  \expandafter\endgroup\next}    

\newcommand\rect[5]{
\draw (#1,#2) rectangle (#3,#4);
\generatex{#5}{#1};
\generatey{#5}{#2};}

\newcommand\join[2]{
\draw(\varx#1,\vary#1)--(\varx#2,\vary#2);}    

 \begin{tikzpicture}

\rect{1}{2}{3}{4}{rectone};
\rect{10}{5}{2}{3}{recttwo};    
\join{rectone}{recttwo};  

\end{tikzpicture}
 \end{document}

Any idea ? I am new to LaTeX and I am sure that all I wrote is terrible, but don't judge me please ! Thanks !!

  • Welcome to TeX.SX! – Philipp Imhof May 4 at 11:43
  • Thank you ! Any idea for my problem ? – Henry May 4 at 12:44
  • All of this is already included in the TikZ system. If you make those rectangles nodes, then the coordinates of the corners are stored in anchors. Internally this looks a bit like what you are doing here, but is IMHO way simpler. – user194703 May 4 at 14:23
2

Instead of

\newcommand\join[2]{
  \draw(\varx#1,\vary#1)--(\varx#2,\vary#2);}

you need to use \csname ... \endcsname to construct a control sequence from its name. For example, \csname varx#1\endcsname.

LaTeX2e' internal macro \@nameuse{<csname>} is helpful when you need to use the \csname ... \endcsname structure frequently. Say, you can write

\makeatletter
\newcommand\join[2]{
  \draw(\@nameuse{varx#1},\@nameuse{vary#1})--(\@nameuse{varx#2},\@nameuse{vary#2});}
\makeatother

A further simplified example:

\documentclass[10pt,a4paper, landscape]{book}
\usepackage{tikz}
\usepackage[french]{babel}     

\newcommand\rect[5]{
  \draw (#1,#2) rectangle (#3,#4);
  % store #1 in macro \varx<#5>
  \expandafter\def\csname varx#5\endcsname{#1};
  % store #2 in macro \vary<#5>
  \expandafter\def\csname vary#5\endcsname{#2};}

\newcommand{\useCoords}[1]{\useCoordX{#1}, \useCoordY{#1}}
\newcommand{\useCoordX}[1]{\csname varx#1\endcsname}
\newcommand{\useCoordY}[1]{\csname vary#1\endcsname}

\newcommand\join[2]{
  \draw (\useCoords{#1}) -- (\useCoords{#2});}

\begin{document}
\begin{tikzpicture}
  \rect{1}{2}{3}{4}{rectone};
  \rect{10}{5}{2}{3}{recttwo};
  \join{rectone}{recttwo};
\end{tikzpicture}
\end{document}

If open to use LaTeX2e internals (doc macros2e gives nice intro to them), you can use

  • \@namedef{<cmd>} ... to replace \expandafter\def\csname <cmd>\endcsname ... and
  • \@nameuse{<cmd>} to replace \csname <cmd>\endcsname.
| improve this answer | |
  • Thank you ! It works very well :) – Henry May 4 at 15:29
1

All these mechanisms are already part of TikZ. For instance, the rectangle connections are as simple as

\documentclass[tikz,border=3mm]{standalone}
\begin{document}
\begin{tikzpicture}
 \draw[local bounding box=A] (1,2) rectangle (3,4);
 \draw[local bounding box=B] (10,5) rectangle (2,3);
 \draw (A.south west) -- (B.south west);
\end{tikzpicture}
\end{document}

enter image description here

There is a plethora of shapes with anchors. For the purposes you are describing there already exist built-in tools in TikZ.

| improve this answer | |
  • Actually, it was rather a way to understand how to store the argument of a macro, than the need to join my two rectangles... But thank you for your help !! – Henry May 4 at 15:31
  • @Henry I was assuming that. This answer is also to tell you that TikZ is "one step ahead". You could think it is a good idea to store, for a shape named A, the x and y coordinates in some macros \shapeAx and \shapeAy, which is similar to what you propose. But what if some user has a sharp called Ax? That's why pgf has mechanisms which schematically defines a macro \def\coordsA{\pgf@x=<x>\pgf@y=<y>} with two dimensions \pgf@x and \pgf@y. With that mechanism you can store an arbitrary amount of attributes without running out of name space. – user194703 May 4 at 19:37
  • Ok I understand. Thank you for your help and your explanations ! – Henry May 4 at 21:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.