2

I don't know if it's right to allow this kind of practice, but I've been asked many times. How do you allow spaces between square brackets and parentheses in the code below? I try to use \@ifnextchar unsuccessfully, perhaps it's easier with expl3

\documentclass{standalone} 
\usepackage{tikz}
\makeatletter
\def\DrawPolygon{\@ifnextchar[{\@DrawPolygon}{\@DrawPolygon[]}}
\def\@DrawPolygon[#1](#2,#3)#4{%
 \begingroup
 \draw[#1] (#2)
     \foreach \pt in {#2,#3}{--(\pt)}--cycle;
 \endgroup
} 
\makeatother

\begin{document} 

\begin{tikzpicture}
\coordinate (A) at (0,0); 
\coordinate (B) at (2,0); 
\coordinate (C) at (2,2); 
\coordinate (D) at (0,3);

\DrawPolygon  [red](A,...,D)  {mypolygon} %ok
% problem with \DrawPolygon  [red] (A,...,D)  {mypolygon}
\end{tikzpicture}
\end{document}
Alain Matthes
  • 95,075

3 Answers3

3

As an alternative to xparse, a simple adjustment to your existing definition would be to change

\def\@DrawPolygon[#1](#2,#3)#4{%
 \begingroup
 \draw[#1] (#2)
     \foreach \pt in {#2,#3}{--(\pt)}--cycle;
 \endgroup
}

to

\def\@DrawPolygon[#1]#2(#3,#4)#5{%
 \begingroup
 \draw[#1] (#3)
     \foreach \pt in {#3,#4}{--(\pt)}--cycle;
 \endgroup
}

which would allow spaces (or anything) between ] and (.

You could of course check that #2 at most contains spaces if you wanted to check for that, but the macro is already silently discarding #4 (now #5) so doing the same for the new #2 doesn't seem too bad.

Alain Matthes
  • 95,075
David Carlisle
  • 757,742
1

You can use xparse. The first argument is optional with default value empty; the second argument is anything from ( to a comma, the third argument anything up to ).

\documentclass{article}
\usepackage{tikz,xparse}

\NewDocumentCommand{\DrawPolygon}{O{}r(,u)m}{%
  \draw[#1] (#2) \foreach \pt in {#2,#3}{--(\pt)}--cycle;
}

\begin{document}

\begin{tikzpicture}
\coordinate (A) at (0,0); \coordinate (B) at (2,0);
\coordinate (C) at (2,2); \coordinate (D) at (0,3);

\DrawPolygon  [red](A,...,D)  {mypolygon}
\end{tikzpicture}
\begin{tikzpicture}
\coordinate (A) at (0,0); \coordinate (B) at (2,0);
\coordinate (C) at (2,2); \coordinate (D) at (0,3);

\DrawPolygon  [red] (A,...,D)  {mypolygon}
\end{tikzpicture}

\end{document}

It would be probably better to avoid u argument type, but for this application it seems adequate.

enter image description here

A code that avoids u:

\ExplSyntaxOn

\NewDocumentCommand{\DrawPolygon}{O{}r()m}
 {
  \am_drawpolygon:nnn { #1 } { #2 } { #3 }
 }

\cs_new_protected:Nn \am_drawpolygon:nnn
 {
  \draw[#1](\clist_item:nn { #2 } { 1 }) \foreach \pt in {#2}{--(\pt)}--cycle;
 }

\ExplSyntaxOff
egreg
  • 1,121,712
  • thanks ! so far I've only seen a few examples with ‘xparse' but I haven't studied it yet. Why it's better to avoid u? Do you have a solution without xparse? – Alain Matthes Feb 10 '20 at 09:35
  • After reading the doc quickly my only problem is r(,u) , more specifically ,u – Alain Matthes Feb 10 '20 at 09:43
  • @AlainMatthes I added the definition without u argument. The original reads: first argument is optional with default value empty: O{}; second argument is anything between ( and ,: r(,); third argument is anything up to ): u) – egreg Feb 10 '20 at 09:44
  • I need time to understand (to learn) the code without u . About the presence of ,u in the first solution, I suppose that it has something to do with #2,#3 – Alain Matthes Feb 10 '20 at 09:52
  • @AlainMatthes There is *no* ,u. It is O{} r(, u) m. The argument type r has to be followed by two tokens. – egreg Feb 10 '20 at 10:14
  • ok now I found ; Backwards Compatibility and I understand ... – Alain Matthes Feb 10 '20 at 10:36
1

Here is another way:

\documentclass[tikz, border=2mm]{standalone}
\usepackage{tikz}
\usepackage{xparse}

\ExplSyntaxOn
\cs_new_protected:Npn \alain_draw_poly:nw #1#2,#3\q_stop
  {
    \group_begin:
    \draw[#1] (#2)
       \foreach \pt in {#2,#3} {--(\pt)} -- cycle;
    \group_end:
  }

\NewDocumentCommand \DrawPolygon { O{} R(){} }
  {
    \alain_draw_poly:nw {#1} #2 \q_stop
  }
\ExplSyntaxOff

\begin{document}

\begin{tikzpicture}
\coordinate (A) at (0,0);
\coordinate (B) at (2,0);
\coordinate (C) at (2,2);
\coordinate (D) at (0,3);

\DrawPolygon  [red] (A,...,D)  {mypolygon}
\end{tikzpicture}

\end{document}

enter image description here

Note: \@DrawPolygon in the MWE doesn't use its #4. Here is an enhanced version of the code that creates a node at the centroid of the polygon, with #4 as the node contents:

\documentclass[tikz, border=2mm]{standalone}
\usepackage{tikz}
\usepackage{xparse}

\ExplSyntaxOn

\seq_new:N \g__alain_pts_seq

\cs_new_protected:Npn \alain_draw_poly:nwn #1#2,#3\q_stop #4
  {
    \group_begin:
    \draw[#1] (#2)
      \foreach \pt in {#2,#3} {--(\pt)} -- cycle;

    \seq_gclear:N \g__alain_pts_seq
    \foreach \pt in {#2,#3}
      { \seq_gput_right:Nx \g__alain_pts_seq { \exp_not:V \pt =1 } }

    \node at (barycentric~cs \c_colon_str \seq_use:Nn \g__alain_pts_seq { , })
      {#4};
    \group_end:
  }

\NewDocumentCommand \DrawPolygon { O{} R(){} m }
  {
    \alain_draw_poly:nwn {#1} #2 \q_stop {#3}
  }
\ExplSyntaxOff

\begin{document}

\begin{tikzpicture}
\coordinate (A) at (0,0);
\coordinate (B) at (2,0);
\coordinate (C) at (2,2);
\coordinate (D) at (0,3);

\DrawPolygon  [red] (A,...,D)  {My polygon}
\end{tikzpicture}

\end{document}

enter image description here

frougon
  • 24,283
  • 1
  • 32
  • 55
  • About #4 yes in my example but it's possible in other cases. I want to learn ... – Alain Matthes Feb 10 '20 at 09:57
  • Right, at first I wanted to use it, but since there is no \node command here, there was no obvious place. I imagine you would like to compute an average coordinate to place a node? – frougon Feb 10 '20 at 10:01
  • Often the macros I use are of this form. Why \q_stop that egreg doesn't use? – Alain Matthes Feb 10 '20 at 10:06
  • 1
    \cs_new_protected:Npn \alain_draw_poly:nw #1#2,#3\q_stop is like a \protected\long\def. Here, #3 is a delimited argument for TeX, \q_stop is the standard delimiter used in such situations in expl3 AFAIK, like \@nil in LaTeX2e. egreg used it here for instance. :-) (#2 is also a delimited argument here, the delimiter being a comma of catcode 12). So, the \cs_new_protected:Npn ... is akin to \protected\long\def\yourmacro #1#2,#3\@nil, if you understand this better. – frougon Feb 10 '20 at 10:12
  • 1
    I added an enhanced version of the code that creates a node at the centroid of the polygon, with #4 as the node contents. – frougon Feb 10 '20 at 10:48